--- /dev/null
+Source: http://ports.ubuntu.com/pool/multiverse/v/virtualbox/virtualbox-guest-dkms_5.1.28-dfsg-1_all.deb
+Version: 5.1.28-dfsg-1
--- /dev/null
+.NOTPARALLEL:
+
+obj-m = vboxguest/ vboxsf/ vboxvideo/
--- /dev/null
+PACKAGE_NAME="virtualbox-guest"
+PACKAGE_VERSION="5.1.28"
+CLEAN="rm -f *.*o"
+BUILT_MODULE_NAME[0]="vboxguest"
+BUILT_MODULE_LOCATION[0]="vboxguest"
+DEST_MODULE_LOCATION[0]="/updates"
+BUILT_MODULE_NAME[1]="vboxsf"
+BUILT_MODULE_LOCATION[1]="vboxsf"
+DEST_MODULE_LOCATION[1]="/updates"
+BUILT_MODULE_NAME[2]="vboxvideo"
+BUILT_MODULE_LOCATION[2]="vboxvideo"
+DEST_MODULE_LOCATION[2]="/updates"
+AUTOINSTALL="yes"
--- /dev/null
+/** @file
+ *
+ * VBox Host Guest Shared Memory Interface (HGSMI).
+ * Host/Guest shared part.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+#ifndef ___VBox_HGSMI_HGSMI_h
+#define ___VBox_HGSMI_HGSMI_h
+
+#include <iprt/assert.h>
+#include <iprt/types.h>
+
+#include <VBox/HGSMI/HGSMIDefs.h>
+#include <VBox/HGSMI/HGSMIChannels.h>
+#include <VBox/HGSMI/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. */
+typedef DECLCALLBACK(int) FNHGSMICHANNELHANDLER(void *pvHandler, uint16_t u16ChannelInfo, void *pvBuffer, HGSMISIZE cbBuffer);
+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
+{
+ HGSMICHANNEL Channels[HGSMI_NUMBER_OF_CHANNELS]; /* Channel handlers indexed by the channel id.
+ * The array is accessed under the instance lock.
+ */
+} HGSMICHANNELINFO;
+
+
+RT_C_DECLS_BEGIN
+
+DECLINLINE(HGSMIBUFFERHEADER *) HGSMIBufferHeaderFromPtr(void *pvBuffer)
+{
+ return (HGSMIBUFFERHEADER *)pvBuffer;
+}
+
+DECLINLINE(uint8_t *) HGSMIBufferDataFromPtr(void *pvBuffer)
+{
+ return (uint8_t *)pvBuffer + sizeof(HGSMIBUFFERHEADER);
+}
+
+DECLINLINE(HGSMIBUFFERTAIL *) HGSMIBufferTailFromPtr(void *pvBuffer,
+ uint32_t u32DataSize)
+{
+ return (HGSMIBUFFERTAIL *)(HGSMIBufferDataFromPtr(pvBuffer) + u32DataSize);
+}
+
+DECLINLINE(HGSMISIZE) HGSMIBufferMinimumSize(void)
+{
+ return sizeof(HGSMIBUFFERHEADER) + sizeof(HGSMIBUFFERTAIL);
+}
+
+DECLINLINE(HGSMIBUFFERHEADER *) HGSMIBufferHeaderFromData(const void *pvData)
+{
+ return (HGSMIBUFFERHEADER *)((uint8_t *)pvData - sizeof(HGSMIBUFFERHEADER));
+}
+
+DECLINLINE(HGSMISIZE) HGSMIBufferRequiredSize(uint32_t u32DataSize)
+{
+ return HGSMIBufferMinimumSize() + u32DataSize;
+}
+
+DECLINLINE(HGSMIOFFSET) HGSMIPointerToOffset(const HGSMIAREA *pArea,
+ const void *pv)
+{
+ return pArea->offBase + (HGSMIOFFSET)((uint8_t *)pv - pArea->pu8Base);
+}
+
+DECLINLINE(void *) HGSMIOffsetToPointer(const HGSMIAREA *pArea,
+ HGSMIOFFSET offBuffer)
+{
+ return pArea->pu8Base + (offBuffer - pArea->offBase);
+}
+
+DECLINLINE(uint8_t *) HGSMIBufferDataFromOffset(const HGSMIAREA *pArea,
+ HGSMIOFFSET offBuffer)
+{
+ void *pvBuffer = HGSMIOffsetToPointer(pArea, offBuffer);
+ return HGSMIBufferDataFromPtr(pvBuffer);
+}
+
+DECLINLINE(HGSMIOFFSET) HGSMIBufferOffsetFromData(const HGSMIAREA *pArea,
+ void *pvData)
+{
+ HGSMIBUFFERHEADER *pHeader = HGSMIBufferHeaderFromData(pvData);
+ return HGSMIPointerToOffset(pArea, pHeader);
+}
+
+DECLINLINE(uint8_t *) HGSMIBufferDataAndChInfoFromOffset(const HGSMIAREA *pArea,
+ HGSMIOFFSET offBuffer,
+ uint16_t *pu16ChannelInfo)
+{
+ HGSMIBUFFERHEADER *pHeader = (HGSMIBUFFERHEADER *)HGSMIOffsetToPointer(pArea, offBuffer);
+ *pu16ChannelInfo = pHeader->u16ChannelInfo;
+ return HGSMIBufferDataFromPtr(pHeader);
+}
+
+uint32_t HGSMIChecksum(HGSMIOFFSET offBuffer,
+ const HGSMIBUFFERHEADER *pHeader,
+ const HGSMIBUFFERTAIL *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 *pv)
+{
+ return (uintptr_t)pv >= (uintptr_t)pArea->pu8Base && (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 *HGSMIHeapBufferAlloc(HGSMIHEAP *pHeap,
+ HGSMISIZE cbBuffer);
+
+void HGSMIHeapBufferFree(HGSMIHEAP *pHeap,
+ void *pvBuf);
+
+void *HGSMIHeapAlloc(HGSMIHEAP *pHeap,
+ HGSMISIZE cbData,
+ uint8_t u8Channel,
+ uint16_t u16ChannelInfo);
+
+void HGSMIHeapFree(HGSMIHEAP *pHeap,
+ void *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 *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_HGSMI_HGSMI_h */
+
--- /dev/null
+/** @file
+ * VBox Host Guest Shared Memory Interface (HGSMI), sHost/Guest shared part.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___VBox_HGSMI_HGSMIChSetup_h
+#define ___VBox_HGSMI_HGSMIChSetup_h
+
+#include <VBox/HGSMI/HGSMI.h>
+
+/* HGSMI setup and configuration channel commands and data structures. */
+#define HGSMI_CC_HOST_FLAGS_LOCATION 0 /* Tell the host the location of HGSMIHOSTFLAGS 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.
+ */
+
+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(0x1)
+/* IRQ is fired, should be accessed under VGAState::lock only */
+#define HGSMIHOSTFLAGS_IRQ UINT32_C(0x2)
+#ifdef VBOX_WITH_WDDM
+/* one or more guest commands is completed, should be accessed under FIFO lock only */
+# define HGSMIHOSTFLAGS_GCOMMAND_COMPLETED UINT32_C(0x4)
+/* watchdog timer interrupt flag (used for debugging), should be accessed under VGAState::lock only */
+# define HGSMIHOSTFLAGS_WATCHDOG UINT32_C(0x8)
+#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 to completing HGSMI 3D and Video Accel respectively,
+ * EMT thread when dealing with HGSMI command processing, etc.
+ * Besides settings/cleaning flags atomically, some each flag has its own special sync restrictions,
+ * see commants for flags definitions above */
+ volatile uint32_t u32HostFlags;
+ uint32_t au32Reserved[3];
+} HGSMIHOSTFLAGS;
+AssertCompileSize(HGSMIHOSTFLAGS, 16);
+
+#endif
+
--- /dev/null
+/** @file
+ *
+ * VBox Host Guest Shared Memory Interface (HGSMI).
+ * Host/Guest shared part.
+ * Channel identifiers.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+#ifndef __HGSMIChannels_h__
+#define __HGSMIChannels_h__
+
+
+/* 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. */
+#define HGSMI_CH_RESERVED (0x00) /* A reserved channel value. */
+
+#define HGSMI_CH_HGSMI (0x01) /* HGCMI: setup and configuration channel. */
+
+#define HGSMI_CH_VBVA (0x02) /* Graphics: VBVA. */
+#define HGSMI_CH_SEAMLESS (0x03) /* Graphics: Seamless with a single guest region. */
+#define HGSMI_CH_SEAMLESS2 (0x04) /* Graphics: Seamless with separate host windows. */
+#define HGSMI_CH_OPENGL (0x05) /* Graphics: OpenGL HW acceleration. */
+
+
+/* Dynamically allocated channel identifiers. */
+#define HGSMI_CH_STRING_FIRST (0x20) /* The first channel index to be used for string mappings (inclusive). */
+#define HGSMI_CH_STRING_LAST (0xff) /* The last channel index for string mappings (inclusive). */
+
+
+/* Check whether the channel identifier is allocated for a dynamic channel. */
+#define HGSMI_IS_DYNAMIC_CHANNEL(_channel) (((uint8_t)(_channel) & 0xE0) != 0)
+
+
+#endif /* !__HGSMIChannels_h__*/
--- /dev/null
+/** @file
+ *
+ * VBox Host Guest Shared Memory Interface (HGSMI).
+ * Host/Guest shared part: types and defines.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+#ifndef ___VBox_HGSMI_HGSMIDefs_h
+#define ___VBox_HGSMI_HGSMIDefs_h
+
+#include <iprt/assert.h>
+#include <iprt/types.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)
+/* 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_HGSMI_HGSMIDefs_h */
--- /dev/null
+/** @file
+ *
+ * VBox Host Guest Shared Memory Interface (HGSMI).
+ * Memory allocator.
+ */
+
+/*
+ * Copyright (C) 2014-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+#ifndef ___VBox_HGSMI_HGSMIMemAlloc_h
+#define ___VBox_HGSMI_HGSMIMemAlloc_h
+
+#include <VBox/HGSMI/HGSMIDefs.h>
+#include <iprt/list.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 *HGSMIMAAlloc(HGSMIMADATA *pMA, HGSMISIZE cb);
+void HGSMIMAFree(HGSMIMADATA *pMA, void *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;
+ Assert(HGSMIMAOrder2Size(order) == cb);
+ return order;
+}
+
+RT_C_DECLS_END
+
+#endif /* !___VBox_HGSMI_HGSMIMemAlloc_h */
--- /dev/null
+/** @file
+ * VirtualBox graphics card port I/O definitions
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___VBox_Hardware_VBoxVideoVBE_h
+#define ___VBox_Hardware_VBoxVideoVBE_h
+
+/* 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
+
+#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_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_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
+
+#define VGA_PORT_HGSMI_HOST 0x3b0
+#define VGA_PORT_HGSMI_GUEST 0x3d0
+
+/* 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
+
+#endif /* !___VBox_Hardware_VBoxVideoVBE_h */
+
--- /dev/null
+/** @file
+ * VBoxGuest - VirtualBox Guest Additions Driver Interface. (ADD,DEV)
+ *
+ * @remarks This is in the process of being split up and usage cleaned up.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___VBox_VBoxGuest_h
+#define ___VBox_VBoxGuest_h
+
+#include <VBox/cdefs.h>
+#include <VBox/types.h>
+#include <iprt/assert.h>
+#include <VBox/VMMDev2.h>
+#include <VBox/VBoxGuest2.h>
+
+
+/** @defgroup grp_vboxguest VirtualBox Guest Additions Device Driver
+ *
+ * Also know as VBoxGuest.
+ *
+ * @{
+ */
+
+/** @defgroup grp_vboxguest_ioc VirtualBox Guest Additions Driver Interface
+ * @{
+ */
+
+/** @todo It would be nice if we could have two defines without paths. */
+
+/** @def VBOXGUEST_DEVICE_NAME
+ * The support device name. */
+/** @def VBOXGUEST_USER_DEVICE_NAME
+ * The support device name of the user accessible device node. */
+
+#if defined(RT_OS_OS2)
+# define VBOXGUEST_DEVICE_NAME "\\Dev\\VBoxGst$"
+
+#elif defined(RT_OS_WINDOWS)
+# 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_HAIKU)
+# define VBOXGUEST_DEVICE_NAME "/dev/misc/vboxguest"
+
+#else /* (PORTME) */
+# define VBOXGUEST_DEVICE_NAME "/dev/vboxguest"
+# if defined(RT_OS_LINUX)
+# define VBOXGUEST_USER_DEVICE_NAME "/dev/vboxuser"
+# endif
+#endif
+
+#ifndef VBOXGUEST_USER_DEVICE_NAME
+# define VBOXGUEST_USER_DEVICE_NAME VBOXGUEST_DEVICE_NAME
+#endif
+
+/** 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(IN_RC) && !defined(IN_RING0_AGNOSTIC) && !defined(IPRT_NO_CRT)
+
+/** @name VBoxGuest IOCTL codes and structures.
+ *
+ * The range 0..15 is for basic driver communication.
+ * The range 16..31 is for HGCM communication.
+ * The range 32..47 is reserved for future use.
+ * The range 48..63 is for OS specific communication.
+ * The 7th bit is reserved for future hacks.
+ * The 8th bit is reserved for distinguishing between 32-bit and 64-bit
+ * processes in future 64-bit guest additions.
+ *
+ * @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(RT_ARCH_AMD64) || defined(RT_ARCH_SPARC64)
+# define VBOXGUEST_IOCTL_FLAG 128
+#elif defined(RT_ARCH_X86) || defined(RT_ARCH_SPARC)
+# define VBOXGUEST_IOCTL_FLAG 0
+#else
+# error "dunno which arch this is!"
+#endif
+/** @} */
+
+/** 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 VBGLBIGREQ
+{
+ /** Magic value (VBGLBIGREQ_MAGIC). */
+ uint32_t u32Magic;
+ /** The size of the data buffer. */
+ uint32_t cbData;
+ /** The user address of the data buffer. */
+ RTR3PTR pvDataR3;
+#if HC_ARCH_BITS == 32
+ uint32_t u32Padding;
+#endif
+/** @todo r=bird: We need a 'rc' field for passing VBox status codes. Reused
+ * some input field as rc on output. */
+} VBGLBIGREQ;
+/** Pointer to a request wrapper for solaris guests. */
+typedef VBGLBIGREQ *PVBGLBIGREQ;
+/** Pointer to a const request wrapper for solaris guests. */
+typedef const VBGLBIGREQ *PCVBGLBIGREQ;
+
+/** The VBGLBIGREQ::u32Magic value (Ryuu Murakami). */
+#define VBGLBIGREQ_MAGIC 0x19520219
+
+
+#if defined(RT_OS_WINDOWS)
+/** @todo Remove IOCTL_CODE later! Integrate it in VBOXGUEST_IOCTL_CODE below. */
+/** @todo r=bird: IOCTL_CODE is supposedly defined in some header included by Windows.h or ntddk.h, which is why it wasn't in the #if 0 earlier. See HostDrivers/Support/SUPDrvIOC.h... */
+# define IOCTL_CODE(DeviceType, Function, Method, Access, DataSize_ignored) \
+ ( ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
+# define VBOXGUEST_IOCTL_CODE_(Function, Size) IOCTL_CODE(FILE_DEVICE_UNKNOWN, 2048 + (Function), METHOD_BUFFERED, FILE_WRITE_ACCESS, 0)
+# define VBOXGUEST_IOCTL_STRIP_SIZE(Code) (Code)
+
+#elif defined(RT_OS_OS2)
+ /* No automatic buffering, size not encoded. */
+# define VBOXGUEST_IOCTL_CATEGORY 0xc2
+# define VBOXGUEST_IOCTL_CODE_(Function, Size) ((unsigned char)(Function))
+# define VBOXGUEST_IOCTL_CATEGORY_FAST 0xc3 /**< Also defined in VBoxGuestA-os2.asm. */
+# define VBOXGUEST_IOCTL_CODE_FAST_(Function) ((unsigned char)(Function))
+# define VBOXGUEST_IOCTL_STRIP_SIZE(Code) (Code)
+
+#elif defined(RT_OS_SOLARIS)
+ /* No automatic buffering, size limited to 255 bytes => use VBGLBIGREQ for everything. */
+# include <sys/ioccom.h>
+# define VBOXGUEST_IOCTL_CODE_(Function, Size) _IOWRN('V', (Function), sizeof(VBGLBIGREQ))
+# define VBOXGUEST_IOCTL_CODE_FAST_(Function) _IO( 'V', (Function))
+# define VBOXGUEST_IOCTL_STRIP_SIZE(Code) (Code)
+
+#elif defined(RT_OS_LINUX)
+ /* No automatic buffering, size limited to 16KB. */
+# include <linux/ioctl.h>
+# define VBOXGUEST_IOCTL_CODE_(Function, Size) _IOC(_IOC_READ|_IOC_WRITE, 'V', (Function), (Size))
+# define VBOXGUEST_IOCTL_CODE_FAST_(Function) _IO( 'V', (Function))
+# define VBOXGUEST_IOCTL_STRIP_SIZE(Code) VBOXGUEST_IOCTL_CODE_(_IOC_NR((Code)), 0)
+
+#elif defined(RT_OS_HAIKU)
+ /* No automatic buffering, size not encoded. */
+ /** @todo do something better */
+# define VBOXGUEST_IOCTL_CODE_(Function, Size) (0x56420000 | (Function))
+# define VBOXGUEST_IOCTL_CODE_FAST_(Function) (0x56420000 | (Function))
+# define VBOXGUEST_IOCTL_STRIP_SIZE(Code) (Code)
+
+#elif defined(RT_OS_FREEBSD) || defined(RT_OS_NETBSD) /** @todo r=bird: Please do it like SUPDRVIOC to keep it as similar as possible. */
+# include <sys/ioccom.h>
+
+# define VBOXGUEST_IOCTL_CODE_(Function, Size) _IOWR('V', (Function), VBGLBIGREQ)
+# define VBOXGUEST_IOCTL_CODE_FAST_(Function) _IO( 'V', (Function))
+# define VBOXGUEST_IOCTL_STRIP_SIZE(Code) IOCBASECMD(Code)
+
+#else /* BSD Like */
+ /* Automatic buffering, size limited to 4KB on *BSD and 8KB on Darwin - commands the limit, 4KB. */
+# include <sys/ioccom.h>
+# define VBOXGUEST_IOCTL_CODE_(Function, Size) _IOC(IOC_INOUT, 'V', (Function), (Size))
+# define VBOXGUEST_IOCTL_CODE_FAST_(Function) _IO('V', (Function))
+# define VBOXGUEST_IOCTL_STRIP_SIZE(uIOCtl) ( (uIOCtl) & ~_IOC(0,0,0,IOCPARM_MASK) )
+#endif
+
+#define VBOXGUEST_IOCTL_CODE(Function, Size) VBOXGUEST_IOCTL_CODE_((Function) | VBOXGUEST_IOCTL_FLAG, Size)
+#define VBOXGUEST_IOCTL_CODE_FAST(Function) VBOXGUEST_IOCTL_CODE_FAST_((Function) | VBOXGUEST_IOCTL_FLAG)
+
+/* Define 32 bit codes to support 32 bit applications requests in the 64 bit guest driver. */
+#ifdef RT_ARCH_AMD64
+# define VBOXGUEST_IOCTL_CODE_32(Function, Size) VBOXGUEST_IOCTL_CODE_(Function, Size)
+# define VBOXGUEST_IOCTL_CODE_FAST_32(Function) VBOXGUEST_IOCTL_CODE_FAST_(Function)
+#endif /* RT_ARCH_AMD64 */
+
+
+
+/** IOCTL to VBoxGuest to query the VMMDev IO port region start.
+ * @remarks Ring-0 only. */
+#define VBOXGUEST_IOCTL_GETVMMDEVPORT VBOXGUEST_IOCTL_CODE(1, sizeof(VBoxGuestPortInfo))
+
+#pragma pack(4)
+typedef struct VBoxGuestPortInfo
+{
+ uint32_t portAddress;
+ struct VMMDevMemory *pVMMDevMemory;
+} VBoxGuestPortInfo;
+
+
+/** IOCTL to VBoxGuest to wait for a VMMDev host notification */
+#define VBOXGUEST_IOCTL_WAITEVENT VBOXGUEST_IOCTL_CODE_(2, sizeof(VBoxGuestWaitEventInfo))
+
+/** @name Result codes for VBoxGuestWaitEventInfo::u32Result
+ * @{
+ */
+/** Successful completion, an event occurred. */
+#define VBOXGUEST_WAITEVENT_OK (0)
+/** Successful completion, timed out. */
+#define VBOXGUEST_WAITEVENT_TIMEOUT (1)
+/** Wait was interrupted. */
+#define VBOXGUEST_WAITEVENT_INTERRUPTED (2)
+/** An error occurred while processing the request. */
+#define VBOXGUEST_WAITEVENT_ERROR (3)
+/** @} */
+
+/** Input and output buffers layout of the IOCTL_VBOXGUEST_WAITEVENT */
+typedef struct VBoxGuestWaitEventInfo
+{
+ /** timeout in milliseconds */
+ uint32_t u32TimeoutIn;
+ /** events to wait for */
+ uint32_t u32EventMaskIn;
+ /** result code */
+ uint32_t u32Result;
+ /** events occurred */
+ uint32_t u32EventFlagsOut;
+} VBoxGuestWaitEventInfo;
+AssertCompileSize(VBoxGuestWaitEventInfo, 16);
+
+
+/** IOCTL to VBoxGuest to perform a VMM request
+ * @remark The data buffer for this IOCtl has an variable size, keep this in mind
+ * on systems where this matters. */
+#define VBOXGUEST_IOCTL_VMMREQUEST(Size) VBOXGUEST_IOCTL_CODE_(3, (Size))
+
+
+/** IOCTL to VBoxGuest to control event filter mask. */
+#define VBOXGUEST_IOCTL_CTL_FILTER_MASK VBOXGUEST_IOCTL_CODE_(4, sizeof(VBoxGuestFilterMaskInfo))
+
+/** Input and output buffer layout of the IOCTL_VBOXGUEST_CTL_FILTER_MASK. */
+typedef struct VBoxGuestFilterMaskInfo
+{
+ uint32_t u32OrMask;
+ uint32_t u32NotMask;
+} VBoxGuestFilterMaskInfo;
+AssertCompileSize(VBoxGuestFilterMaskInfo, 8);
+#pragma pack()
+
+/** IOCTL to VBoxGuest to interrupt (cancel) any pending WAITEVENTs and return.
+ * Handled inside the guest additions and not seen by the host at all.
+ * @see VBOXGUEST_IOCTL_WAITEVENT */
+#define VBOXGUEST_IOCTL_CANCEL_ALL_WAITEVENTS VBOXGUEST_IOCTL_CODE_(5, 0)
+
+/** IOCTL to VBoxGuest to perform backdoor logging.
+ * The argument is a string buffer of the specified size. */
+#define VBOXGUEST_IOCTL_LOG(Size) VBOXGUEST_IOCTL_CODE_(6, (Size))
+
+/** 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 (VBOXGUEST_IOCTL_CHANGE_BALLOON). */
+#define VBOXGUEST_IOCTL_CHECK_BALLOON VBOXGUEST_IOCTL_CODE_(7, sizeof(VBoxGuestCheckBalloonInfo))
+
+/** Output buffer layout of the VBOXGUEST_IOCTL_CHECK_BALLOON. */
+typedef struct VBoxGuestCheckBalloonInfo
+{
+ /** 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. */
+ uint32_t fHandleInR3;
+} VBoxGuestCheckBalloonInfo;
+AssertCompileSize(VBoxGuestCheckBalloonInfo, 8);
+
+
+/** 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 VBOXGUEST_IOCTL_CHANGE_BALLOON VBOXGUEST_IOCTL_CODE_(8, sizeof(VBoxGuestChangeBalloonInfo))
+
+/** Input buffer layout of the VBOXGUEST_IOCTL_CHANGE_BALLOON request.
+ * Information about a memory chunk used to inflate or deflate the balloon. */
+typedef struct VBoxGuestChangeBalloonInfo
+{
+ /** Address of the chunk. */
+ uint64_t u64ChunkAddr;
+ /** true = inflate, false = deflate. */
+ uint32_t fInflate;
+ /** Alignment padding. */
+ uint32_t u32Align;
+} VBoxGuestChangeBalloonInfo;
+AssertCompileSize(VBoxGuestChangeBalloonInfo, 16);
+
+/** IOCTL to VBoxGuest to write guest core. */
+#define VBOXGUEST_IOCTL_WRITE_CORE_DUMP VBOXGUEST_IOCTL_CODE(9, sizeof(VBoxGuestWriteCoreDump))
+
+/** Input and output buffer layout of the VBOXGUEST_IOCTL_WRITE_CORE
+ * request. */
+typedef struct VBoxGuestWriteCoreDump
+{
+ /** Flags (reserved, MBZ). */
+ uint32_t fFlags;
+} VBoxGuestWriteCoreDump;
+AssertCompileSize(VBoxGuestWriteCoreDump, 4);
+
+/** IOCTL to VBoxGuest to update the mouse status features. */
+# define VBOXGUEST_IOCTL_SET_MOUSE_STATUS VBOXGUEST_IOCTL_CODE_(10, sizeof(uint32_t))
+
+#ifdef VBOX_WITH_HGCM
+/** IOCTL to VBoxGuest to connect to a HGCM service. */
+# define VBOXGUEST_IOCTL_HGCM_CONNECT VBOXGUEST_IOCTL_CODE(16, sizeof(VBoxGuestHGCMConnectInfo))
+
+/** IOCTL to VBoxGuest to disconnect from a HGCM service. */
+# define VBOXGUEST_IOCTL_HGCM_DISCONNECT VBOXGUEST_IOCTL_CODE(17, sizeof(VBoxGuestHGCMDisconnectInfo))
+
+/** IOCTL to VBoxGuest to make a call to a HGCM service.
+ * @see VBoxGuestHGCMCallInfo */
+# define VBOXGUEST_IOCTL_HGCM_CALL(Size) VBOXGUEST_IOCTL_CODE(18, (Size))
+
+/** IOCTL to VBoxGuest to make a timed call to a HGCM service. */
+# define VBOXGUEST_IOCTL_HGCM_CALL_TIMED(Size) VBOXGUEST_IOCTL_CODE(20, (Size))
+
+/** IOCTL to VBoxGuest passed from the Kernel Mode driver, but containing a user mode data in VBoxGuestHGCMCallInfo
+ * the driver received from the UM. Called in the context of the process passing the data.
+ * @see VBoxGuestHGCMCallInfo */
+# define VBOXGUEST_IOCTL_HGCM_CALL_USERDATA(Size) VBOXGUEST_IOCTL_CODE(21, (Size))
+
+# ifdef RT_ARCH_AMD64
+/** @name IOCTL numbers that 32-bit clients, like the Windows OpenGL guest
+ * driver, will use when taking to a 64-bit driver.
+ * @remarks These are only used by the driver implementation!
+ * @{*/
+# define VBOXGUEST_IOCTL_HGCM_CONNECT_32 VBOXGUEST_IOCTL_CODE_32(16, sizeof(VBoxGuestHGCMConnectInfo))
+# define VBOXGUEST_IOCTL_HGCM_DISCONNECT_32 VBOXGUEST_IOCTL_CODE_32(17, sizeof(VBoxGuestHGCMDisconnectInfo))
+# define VBOXGUEST_IOCTL_HGCM_CALL_32(Size) VBOXGUEST_IOCTL_CODE_32(18, (Size))
+# define VBOXGUEST_IOCTL_HGCM_CALL_TIMED_32(Size) VBOXGUEST_IOCTL_CODE_32(20, (Size))
+/** @} */
+# endif /* RT_ARCH_AMD64 */
+
+/** Get the pointer to the first HGCM parameter. */
+# define VBOXGUEST_HGCM_CALL_PARMS(a) ( (HGCMFunctionParameter *)((uint8_t *)(a) + sizeof(VBoxGuestHGCMCallInfo)) )
+/** Get the pointer to the first HGCM parameter in a 32-bit request. */
+# define VBOXGUEST_HGCM_CALL_PARMS32(a) ( (HGCMFunctionParameter32 *)((uint8_t *)(a) + sizeof(VBoxGuestHGCMCallInfo)) )
+
+#endif /* VBOX_WITH_HGCM */
+
+#ifdef VBOX_WITH_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 VBOXGUEST_IOCTL_DPC_LATENCY_CHECKER VBOXGUEST_IOCTL_CODE_(30, 0)
+#endif
+
+/** IOCTL to for setting the mouse driver callback. (kernel only) */
+/** @note The callback will be called in interrupt context with the VBoxGuest
+ * device event spinlock held. */
+#define VBOXGUEST_IOCTL_SET_MOUSE_NOTIFY_CALLBACK VBOXGUEST_IOCTL_CODE(31, sizeof(VBoxGuestMouseSetNotifyCallback))
+
+typedef DECLCALLBACK(void) FNVBOXGUESTMOUSENOTIFY(void *pfnUser);
+typedef FNVBOXGUESTMOUSENOTIFY *PFNVBOXGUESTMOUSENOTIFY;
+
+/** Input buffer for VBOXGUEST_IOCTL_INTERNAL_SET_MOUSE_NOTIFY_CALLBACK. */
+typedef struct VBoxGuestMouseSetNotifyCallback
+{
+ /**
+ * Mouse notification callback.
+ *
+ * @param pvUser The callback argument.
+ */
+ PFNVBOXGUESTMOUSENOTIFY pfnNotify;
+ /** The callback argument*/
+ void *pvUser;
+} VBoxGuestMouseSetNotifyCallback;
+
+
+typedef enum VBOXGUESTCAPSACQUIRE_FLAGS
+{
+ VBOXGUESTCAPSACQUIRE_FLAGS_NONE = 0,
+ /* configures VBoxGuest to use the specified caps in Acquire mode, w/o making any caps acquisition/release.
+ * so far it is only possible to set acquire mode for caps, but not clear it,
+ * so u32NotMask is ignored for this request */
+ VBOXGUESTCAPSACQUIRE_FLAGS_CONFIG_ACQUIRE_MODE,
+ /* to ensure enum is 32bit*/
+ VBOXGUESTCAPSACQUIRE_FLAGS_32bit = 0x7fffffff
+} VBOXGUESTCAPSACQUIRE_FLAGS;
+
+typedef struct VBoxGuestCapsAquire
+{
+ /* result status
+ * VINF_SUCCESS - on success
+ * VERR_RESOURCE_BUSY - some caps in the u32OrMask are acquired by some other VBoxGuest connection.
+ * NOTE: no u32NotMask caps are cleaned in this case, i.e. no modifications are done on failure
+ * VER_INVALID_PARAMETER - invalid Caps are specified with either u32OrMask or u32NotMask. No modifications are done on failure.
+ */
+ int32_t rc;
+ /* Acquire command */
+ VBOXGUESTCAPSACQUIRE_FLAGS enmFlags;
+ /* caps to acquire, OR-ed VMMDEV_GUEST_SUPPORTS_XXX flags */
+ uint32_t u32OrMask;
+ /* caps to release, OR-ed VMMDEV_GUEST_SUPPORTS_XXX flags */
+ uint32_t u32NotMask;
+} VBoxGuestCapsAquire;
+
+/** IOCTL to for Acquiring/Releasing Guest Caps
+ * This is used for multiple purposes:
+ * 1. By doing Acquire r3 client application (e.g. VBoxTray) claims it will use
+ * the given connection for performing operations like Seamles or 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.
+ **/
+#define VBOXGUEST_IOCTL_GUEST_CAPS_ACQUIRE VBOXGUEST_IOCTL_CODE(32, sizeof(VBoxGuestCapsAquire))
+
+/** IOCTL to VBoxGuest to set guest capabilities. */
+#define VBOXGUEST_IOCTL_SET_GUEST_CAPABILITIES VBOXGUEST_IOCTL_CODE_(33, sizeof(VBoxGuestSetCapabilitiesInfo))
+
+/** Input and output buffer layout of the VBOXGUEST_IOCTL_SET_GUEST_CAPABILITIES
+ * IOCtl. */
+typedef struct VBoxGuestSetCapabilitiesInfo
+{
+ uint32_t u32OrMask;
+ uint32_t u32NotMask;
+} VBoxGuestSetCapabilitiesInfo;
+AssertCompileSize(VBoxGuestSetCapabilitiesInfo, 8);
+
+
+#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 VBOXGUESTOS2IDCCONNECT
+{
+ /** VMMDEV_VERSION. */
+ uint32_t u32Version;
+ /** Opaque session handle. */
+ uint32_t u32Session;
+
+ /**
+ * The 32-bit service entry point.
+ *
+ * @returns VBox status code.
+ * @param u32Session The above session handle.
+ * @param iFunction The requested function.
+ * @param pvData 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 cbData The size of the data buffer.
+ * @param pcbDataReturned Where to store the amount of data that's returned.
+ * This can be NULL if pvData is NULL.
+ */
+ DECLCALLBACKMEMBER(int, pfnServiceEP)(uint32_t u32Session, unsigned iFunction, void *pvData, size_t cbData, size_t *pcbDataReturned);
+
+ /** 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,
+ * void far *fpvData, uint16_t cbData, uint16_t far *pcbDataReturned);
+ * @endcode
+ */
+ RTFAR16 fpfnServiceEP;
+
+ /** 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;
+} VBOXGUESTOS2IDCCONNECT;
+/** Pointer to VBOXGUESTOS2IDCCONNECT buffer. */
+typedef VBOXGUESTOS2IDCCONNECT *PVBOXGUESTOS2IDCCONNECT;
+
+/** OS/2 specific: IDC client disconnect request.
+ *
+ * This takes no input and it doesn't return anything. Obviously this
+ * is only recognized if it arrives thru the IDC service EP.
+ */
+# define VBOXGUEST_IOCTL_OS2_IDC_DISCONNECT VBOXGUEST_IOCTL_CODE(48, sizeof(uint32_t))
+
+#endif /* RT_OS_OS2 */
+
+#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
+
--- /dev/null
+/** @file
+ * VBoxGuest - VirtualBox Guest Additions Driver Interface, Mixed Up Mess.
+ * (ADD,DEV)
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___VBox_VBoxGuest2_h
+#define ___VBox_VBoxGuest2_h
+
+#include <iprt/assert.h>
+
+#ifdef VBOX_WITH_HGCM
+# include <VBox/VMMDev2.h>
+
+/** @addtogroup grp_vmmdev
+ * @{ */
+
+/**
+ * HGCM connect info structure.
+ *
+ * This is used by VBOXGUEST_IOCTL_HGCM_CONNECT and in VbglR0.
+ *
+ * @ingroup grp_vboxguest
+ */
+# pragma pack(1) /* explicit packing for good measure. */
+typedef struct VBoxGuestHGCMConnectInfo
+{
+ int32_t result; /**< OUT */
+ HGCMServiceLocation Loc; /**< IN */
+ uint32_t u32ClientID; /**< OUT */
+} VBoxGuestHGCMConnectInfo;
+AssertCompileSize(VBoxGuestHGCMConnectInfo, 4+4+128+4);
+# pragma pack()
+
+
+/**
+ * HGCM connect info structure.
+ *
+ * This is used by VBOXGUEST_IOCTL_HGCM_DISCONNECT and in VbglR0.
+ *
+ * @ingroup grp_vboxguest
+ */
+typedef struct VBoxGuestHGCMDisconnectInfo
+{
+ int32_t result; /**< OUT */
+ uint32_t u32ClientID; /**< IN */
+} VBoxGuestHGCMDisconnectInfo;
+AssertCompileSize(VBoxGuestHGCMDisconnectInfo, 8);
+
+/**
+ * HGCM call info structure.
+ *
+ * This is used by VBOXGUEST_IOCTL_HGCM_CALL.
+ *
+ * @ingroup grp_vboxguest
+ */
+typedef struct VBoxGuestHGCMCallInfo
+{
+ int32_t result; /**< OUT Host HGCM return code.*/
+ uint32_t u32ClientID; /**< IN The id of the caller. */
+ uint32_t u32Function; /**< IN Function number. */
+ uint32_t cParms; /**< IN How many parms. */
+ /* Parameters follow in form HGCMFunctionParameter aParms[cParms] */
+} VBoxGuestHGCMCallInfo;
+AssertCompileSize(VBoxGuestHGCMCallInfo, 16);
+
+
+/**
+ * HGCM call info structure.
+ *
+ * This is used by VBOXGUEST_IOCTL_HGCM_CALL_TIMED.
+ *
+ * @ingroup grp_vboxguest
+ */
+# pragma pack(1) /* explicit packing for good measure. */
+typedef struct VBoxGuestHGCMCallInfoTimed
+{
+ uint32_t u32Timeout; /**< IN How long to wait for completion before cancelling the call. */
+ uint32_t fInterruptible; /**< IN Is this request interruptible? */
+ VBoxGuestHGCMCallInfo info; /**< IN/OUT The rest of the call information. Placed after the timeout
+ * so that the parameters follow as they would for a normal call. */
+ /* Parameters follow in form HGCMFunctionParameter aParms[cParms] */
+} VBoxGuestHGCMCallInfoTimed;
+AssertCompileSize(VBoxGuestHGCMCallInfoTimed, 8+16);
+# pragma pack()
+
+/** @} */
+
+#endif /* VBOX_WITH_HGCM */
+
+#endif
+
--- /dev/null
+/** @file
+ * VBoxGuestLib - VirtualBox Guest Additions Library.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___VBox_VBoxGuestLib_h
+#define ___VBox_VBoxGuestLib_h
+
+#include <VBox/types.h>
+#include <VBox/VMMDev2.h>
+#include <VBox/VMMDev.h> /* grumble */
+#ifdef IN_RING0
+# include <VBox/VBoxGuest.h>
+# include <VBox/VBoxGuest2.h>
+#endif
+
+
+/** @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.
+ * @{
+ */
+#if defined(IN_RING0) && !defined(IN_RING0_AGNOSTIC)
+/** @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(type) VBOXCALL
+# else
+# define DECLR0VBGL(type) type VBOXCALL
+# endif
+# define DECLVBGL(type) DECLR0VBGL(type)
+
+
+# ifdef VBGL_VBOXGUEST
+
+/**
+ * The library initialization function to be used by the main
+ * VBoxGuest system driver.
+ *
+ * @return VBox status code.
+ */
+DECLVBGL(int) VbglInitPrimary(RTIOPORT portVMMDev, struct VMMDevMemory *pVMMDevMemory);
+
+# else
+
+/**
+ * The library initialization function to be used by all drivers
+ * other than the main VBoxGuest system driver.
+ *
+ * @return VBox status code.
+ */
+DECLVBGL(int) VbglInitClient(void);
+
+# endif
+
+/**
+ * The library termination function.
+ */
+DECLVBGL(void) VbglTerminate (void);
+
+
+/** @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.
+ */
+DECLVBGL(int) VbglGRAlloc(VMMDevRequestHeader **ppReq, size_t cbReq, VMMDevRequestType enmReqType);
+
+/**
+ * Perform the generic request.
+ *
+ * @param pReq pointer the request structure.
+ *
+ * @return VBox status code.
+ */
+DECLVBGL(int) VbglGRPerform (VMMDevRequestHeader *pReq);
+
+/**
+ * Free the generic request memory.
+ *
+ * @param pReq pointer the request structure.
+ *
+ * @return VBox status code.
+ */
+DECLVBGL(void) VbglGRFree (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.
+ */
+DECLVBGL(int) VbglGRVerify (const VMMDevRequestHeader *pReq, size_t cbReq);
+/** @} */
+
+# ifdef VBOX_WITH_HGCM
+
+# 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 DECLCALLBACK(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 pConnectInfo The request data.
+ * @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 (VBoxGuestHGCMConnectInfo *pConnectInfo,
+ 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 pDisconnectInfo The request data.
+ * @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 (VBoxGuestHGCMDisconnectInfo *pDisconnectInfo,
+ 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 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 (VBoxGuestHGCMCallInfo *pCallInfo, uint32_t cbCallInfo, uint32_t fFlags,
+ 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 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 (VBoxGuestHGCMCallInfo *pCallInfo, uint32_t cbCallInfo, uint32_t fFlags,
+ 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 */
+
+struct VBGLHGCMHANDLEDATA;
+typedef struct VBGLHGCMHANDLEDATA *VBGLHGCMHANDLE;
+
+/** @name HGCM functions
+ * @{
+ */
+
+/**
+ * Connect to a service.
+ *
+ * @param pHandle Pointer to variable that will hold a handle to be used
+ * further in VbglHGCMCall and VbglHGCMClose.
+ * @param pData Connection information structure.
+ *
+ * @return VBox status code.
+ */
+DECLVBGL(int) VbglHGCMConnect (VBGLHGCMHANDLE *pHandle, VBoxGuestHGCMConnectInfo *pData);
+
+/**
+ * Connect to a service.
+ *
+ * @param handle Handle of the connection.
+ * @param pData Disconnect request information structure.
+ *
+ * @return VBox status code.
+ */
+DECLVBGL(int) VbglHGCMDisconnect (VBGLHGCMHANDLE handle, VBoxGuestHGCMDisconnectInfo *pData);
+
+/**
+ * Call to a service.
+ *
+ * @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.
+ */
+DECLVBGL(int) VbglHGCMCall (VBGLHGCMHANDLE handle, VBoxGuestHGCMCallInfo *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.
+ */
+DECLVBGL(int) VbglHGCMCallUserData (VBGLHGCMHANDLE handle, VBoxGuestHGCMCallInfo *pData, uint32_t cbData);
+
+/**
+ * Call to a service with timeout.
+ *
+ * @param handle Handle of the connection.
+ * @param pData Call request information structure, including function parameters.
+ * @param cbData Length in bytes of data.
+ * @param cMillies Timeout in milliseconds. Use RT_INDEFINITE_WAIT to wait forever.
+ *
+ * @return VBox status code.
+ */
+DECLVBGL(int) VbglHGCMCallTimed(VBGLHGCMHANDLE handle, VBoxGuestHGCMCallInfoTimed *pData, uint32_t cbData);
+/** @} */
+
+/** @name Undocumented helpers for talking to the Chromium OpenGL Host Service
+ * @{ */
+typedef VBGLHGCMHANDLE VBGLCRCTLHANDLE;
+DECLVBGL(int) VbglR0CrCtlCreate(VBGLCRCTLHANDLE *phCtl);
+DECLVBGL(int) VbglR0CrCtlDestroy(VBGLCRCTLHANDLE hCtl);
+DECLVBGL(int) VbglR0CrCtlConConnect(VBGLCRCTLHANDLE hCtl, HGCMCLIENTID *pidClient);
+DECLVBGL(int) VbglR0CrCtlConDisconnect(VBGLCRCTLHANDLE hCtl, HGCMCLIENTID idClient);
+DECLVBGL(int) VbglR0CrCtlConCall(VBGLCRCTLHANDLE hCtl, struct VBoxGuestHGCMCallInfo *pCallInfo, int cbCallInfo);
+DECLVBGL(int) VbglR0CrCtlConCallUserData(VBGLCRCTLHANDLE hCtl, struct VBoxGuestHGCMCallInfo *pCallInfo, int cbCallInfo);
+/** @} */
+
+# endif /* !VBGL_VBOXGUEST */
+
+# endif /* VBOX_WITH_HGCM */
+
+
+/**
+ * Initialize the heap.
+ *
+ * @returns VBox status code.
+ */
+DECLVBGL(int) VbglPhysHeapInit (void);
+
+/**
+ * Shutdown the heap.
+ */
+DECLVBGL(void) VbglPhysHeapTerminate (void);
+
+/**
+ * Allocate a memory block.
+ *
+ * @returns Virtual address of the allocated memory block.
+ * @param cbSize Size of block to be allocated.
+ */
+DECLVBGL(void *) VbglPhysHeapAlloc (uint32_t cbSize);
+
+/**
+ * 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.
+ */
+DECLVBGL(uint32_t) VbglPhysHeapGetPhysAddr(void *pv);
+
+/**
+ * Free a memory block.
+ *
+ * @param pv Virtual address of memory block.
+ */
+DECLVBGL(void) VbglPhysHeapFree(void *pv);
+
+DECLVBGL(int) VbglQueryVMMDevMemory (VMMDevMemory **ppVMMDevMemory);
+DECLR0VBGL(bool) VbglR0CanUsePhysPageList(void);
+
+# ifndef VBOX_GUEST
+/** @name Mouse
+ * @{ */
+DECLVBGL(int) VbglSetMouseNotifyCallback(PFNVBOXGUESTMOUSENOTIFY pfnNotify, void *pvUser);
+DECLVBGL(int) VbglGetMouseStatus(uint32_t *pfFeatures, uint32_t *px, uint32_t *py);
+DECLVBGL(int) VbglSetMouseStatus(uint32_t fFeatures);
+/** @} */
+# endif /* VBOX_GUEST */
+
+#endif /* IN_RING0 && !IN_RING0_AGNOSTIC */
+
+/** @} */
+
+
+/** @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) DECLHIDDEN(type) VBOXCALL
+
+/** @name General-purpose functions
+ * @{ */
+VBGLR3DECL(int) VbglR3Init(void);
+VBGLR3DECL(int) VbglR3InitUser(void);
+VBGLR3DECL(void) VbglR3Term(void);
+# ifdef ___iprt_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) 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);
+
+/** @} */
+
+/** @name Shared clipboard
+ * @{ */
+VBGLR3DECL(int) VbglR3ClipboardConnect(HGCMCLIENTID *pidClient);
+VBGLR3DECL(int) VbglR3ClipboardDisconnect(HGCMCLIENTID idClient);
+VBGLR3DECL(int) VbglR3ClipboardGetHostMsg(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) VbglR3ClipboardReportFormats(HGCMCLIENTID idClient, uint32_t fFormats);
+VBGLR3DECL(int) VbglR3ClipboardWriteData(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb);
+/** @} */
+
+/** @name Seamless mode
+ * @{ */
+VBGLR3DECL(int) VbglR3SeamlessSetCap(bool fState);
+VBGLR3DECL(int) VbglR3SeamlessWaitEvent(VMMDevSeamlessMode *pMode);
+VBGLR3DECL(int) VbglR3SeamlessSendRects(uint32_t cRects, PRTRECT pRects);
+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(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 VM Statistics
+ * @{ */
+VBGLR3DECL(int) VbglR3StatQueryInterval(uint32_t *pu32Interval);
+VBGLR3DECL(int) VbglR3StatReport(VMMDevReportGuestStats *pReq);
+/** @} */
+
+/** @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);
+
+/** @} */
+
+# 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(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) 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);
+/** @} */
+
+/** @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);
+VBGLR3DECL(int) VbglR3SharedFolderGetMountPrefix(char **ppszPrefix);
+VBGLR3DECL(int) VbglR3SharedFolderGetMountDir(char **ppszDir);
+/** @} */
+# 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;
+
+/* General message handling on the guest. */
+VBGLR3DECL(int) VbglR3GuestCtrlConnect(uint32_t *pidClient);
+VBGLR3DECL(int) VbglR3GuestCtrlDisconnect(uint32_t uClientId);
+VBGLR3DECL(int) VbglR3GuestCtrlMsgFilterSet(uint32_t uClientId, uint32_t uValue, uint32_t uMaskAdd, uint32_t uMaskRemove);
+VBGLR3DECL(int) VbglR3GuestCtrlMsgFilterUnset(uint32_t uClientId);
+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 uClientId);
+VBGLR3DECL(int) VbglR3GuestCtrlMsgWaitFor(uint32_t uClientId, uint32_t *puMsg, uint32_t *puNumParms);
+VBGLR3DECL(int) VbglR3GuestCtrlCancelPendingWaits(HGCMCLIENTID idClient);
+/* Guest session handling. */
+VBGLR3DECL(int) VbglR3GuestCtrlSessionClose(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t fFlags);
+VBGLR3DECL(int) VbglR3GuestCtrlSessionNotify(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uType, uint32_t uResult);
+VBGLR3DECL(int) VbglR3GuestCtrlSessionGetOpen(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puProtocol, char *pszUser, uint32_t cbUser,
+ char *pszPassword, uint32_t cbPassword, char *pszDomain, uint32_t cbDomain,
+ uint32_t *pfFlags, uint32_t *pidSession);
+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);
+/* Guest process execution. */
+VBGLR3DECL(int) VbglR3GuestCtrlProcGetStart(PVBGLR3GUESTCTRLCMDCTX pCtx, char *pszCmd, uint32_t cbCmd, uint32_t *pfFlags,
+ char *pszArgs, uint32_t cbArgs, uint32_t *puNumArgs, char *pszEnv, uint32_t *pcbEnv,
+ uint32_t *puNumEnvVars, char *pszUser, uint32_t cbUser, char *pszPassword,
+ uint32_t cbPassword, uint32_t *puTimeoutMS, uint32_t *puPriority,
+ uint64_t *puAffinity, uint32_t cbAffinity, uint32_t *pcAffinity);
+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);
+/* 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) VbglR3GuestCtrlFileCbWrite(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, uint32_t uWritten);
+VBGLR3DECL(int) VbglR3GuestCtrlFileCbSeek(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, uint64_t uOffActual);
+VBGLR3DECL(int) VbglR3GuestCtrlFileCbTell(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, uint64_t uOffActual);
+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
+ * @{ */
+VBGLR3DECL(int) VbglR3RegisterSharedModule(char *pszModuleName, char *pszVersion, RTGCPTR64 GCBaseAddr, uint32_t cbModule,
+ unsigned cRegions, 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. */
+ uint32_t uProtocol;
+ /** Number of parameters retrieved for the current command. */
+ uint32_t uNumParms;
+ /** Max chunk size (in bytes) for data transfers. */
+ uint32_t cbMaxChunkSize;
+} VBGLR3GUESTDNDCMDCTX, *PVBGLR3GUESTDNDCMDCTX;
+
+typedef struct VBGLR3DNDHGCMEVENT
+{
+ uint32_t uType; /** The event type this struct contains. */
+ uint32_t uScreenId; /** Screen ID this request belongs to. */
+ char *pszFormats; /** Format list (\r\n separated). */
+ uint32_t cbFormats; /** Size (in bytes) of pszFormats (\0 included). */
+ union
+ {
+ struct
+ {
+ uint32_t uXpos; /** X position of guest screen. */
+ uint32_t uYpos; /** Y position of guest screen. */
+ uint32_t uDefAction; /** Proposed DnD action. */
+ uint32_t uAllActions; /** Allowed DnD actions. */
+ } a; /** Values used in init, move and drop event type. */
+ struct
+ {
+ void *pvData; /** Data request. */
+ uint32_t cbData; /** Size (in bytes) of pvData. */
+ } b; /** Values used in drop data event type. */
+ } u;
+} VBGLR3DNDHGCMEVENT;
+typedef VBGLR3DNDHGCMEVENT *PVBGLR3DNDHGCMEVENT;
+typedef const PVBGLR3DNDHGCMEVENT CPVBGLR3DNDHGCMEVENT;
+VBGLR3DECL(int) VbglR3DnDConnect(PVBGLR3GUESTDNDCMDCTX pCtx);
+VBGLR3DECL(int) VbglR3DnDDisconnect(PVBGLR3GUESTDNDCMDCTX pCtx);
+
+VBGLR3DECL(int) VbglR3DnDRecvNextMsg(PVBGLR3GUESTDNDCMDCTX pCtx, CPVBGLR3DNDHGCMEVENT pEvent);
+
+VBGLR3DECL(int) VbglR3DnDHGSendAckOp(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uAction);
+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, uint32_t uDefAction, uint32_t uAllActions, const char* pcszFormats, uint32_t cbFormats);
+VBGLR3DECL(int) VbglR3DnDGHSendData(PVBGLR3GUESTDNDCMDCTX pCtx, const char *pszFormat, void *pvData, uint32_t cbData);
+VBGLR3DECL(int) VbglR3DnDGHSendError(PVBGLR3GUESTDNDCMDCTX pCtx, int rcOp);
+# endif /* VBOX_WITH_DRAG_AND_DROP_GH */
+/** @} */
+# endif /* VBOX_WITH_DRAG_AND_DROP */
+
+/* Generic Host Channel Service. */
+VBGLR3DECL(int) VbglR3HostChannelInit(uint32_t *pu32HGCMClientId);
+VBGLR3DECL(void) VbglR3HostChannelTerm(uint32_t u32HGCMClientId);
+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);
+/** @} */
+
+#endif /* IN_RING3 */
+/** @} */
+
+RT_C_DECLS_END
+
+/** @} */
+
+#endif
+
--- /dev/null
+/* $Id: VBoxGuestLibSharedFolders.h $ */
+/** @file
+ * VBoxGuestLib - Central calls header.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___VBox_VBoxGuestLibSharedFolders_h_
+#define ___VBox_VBoxGuestLibSharedFolders_h_
+
+#include <VBox/VBoxGuestLib.h>
+#include <VBox/shflsvc.h>
+
+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
+
--- /dev/null
+/** @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-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+#define RT_MANGLER(symbol) VBoxGuest_##symbol
+#include <iprt/mangling.h>
+
--- /dev/null
+/** @file
+ * VirtualBox Video interface.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___VBox_VBoxVideo_h
+#define ___VBox_VBoxVideo_h
+
+#include <VBox/VMMDev.h>
+#include <VBox/Hardware/VBoxVideoVBE.h>
+
+#include <iprt/cdefs.h>
+#include <iprt/types.h>
+
+/*
+ * 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
+
+/* 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 0x00010000
+/* asynch completion is performed by issuing the event */
+#define VBOXVHWACMD_FLAG_GH_ASYNCH_EVENT 0x00000001
+/* issue interrupt on asynch completion */
+#define VBOXVHWACMD_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 setting the VBOXVHWACMD_FLAG_HG_ASYNCH_RETURNED flag */
+#define VBOXVHWACMD_FLAG_GH_ASYNCH_NOCOMPLETION 0x00000004
+/* the host has copied the VBOXVHWACMD_FLAG_GH_ASYNCH_NOCOMPLETION command and returned it to the guest */
+#define VBOXVHWACMD_FLAG_HG_ASYNCH_RETURNED 0x00020000
+/* this is the host->host cmd, i.e. a configuration command posted by the host to the framebuffer */
+#define VBOXVHWACMD_FLAG_HH_CMD 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(_s) (VBOXVHWACMD_HEADSIZE() + (_s))
+#define VBOXVHWACMD_SIZE(_tCmd) (VBOXVHWACMD_SIZE_FROMBODYSIZE(sizeof(_tCmd)))
+typedef unsigned int VBOXVHWACMD_LENGTH;
+typedef uint64_t VBOXVHWA_SURFHANDLE;
+#define VBOXVHWA_SURFHANDLE_INVALID 0ULL
+#define VBOXVHWACMD_BODY(_p, _t) ((_t*)(_p)->body)
+#define VBOXVHWACMD_HEAD(_pb) ((VBOXVHWACMD*)((uint8_t *)(_pb) - 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_OFFSETOF(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 DECLCALLBACK(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
+#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(_size) (sizeof(VBVAHOSTCMD) + (_size))
+#define VBVAHOSTCMD_BODY(_pCmd, _tBody) ((_tBody*)(_pCmd)->body)
+#define VBVAHOSTCMD_HDR(_pBody) ((VBVAHOSTCMD*)(((uint8_t*)_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;
+
+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. */
+#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;
+
+/* 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 (though this is
+ * currently unlikely).
+ * @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 *) VBoxSHGSMIBufferData (const VBOXSHGSMIHEADER* pHeader)
+{
+ return (uint8_t *)pHeader + sizeof (VBOXSHGSMIHEADER);
+}
+
+#define VBoxSHGSMIBufferHeaderSize() (sizeof (VBOXSHGSMIHEADER))
+
+DECLINLINE(PVBOXSHGSMIHEADER) VBoxSHGSMIBufferHeader (const void *pvData)
+{
+ return (PVBOXSHGSMIHEADER)((uint8_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;
+
+typedef struct VBOXVDMA_CTL
+{
+ VBOXVDMA_CTL_TYPE enmCtl;
+ uint32_t u32Offset;
+ int32_t i32Result;
+} VBOXVDMA_CTL, *PVBOXVDMA_CTL;
+
+typedef struct VBOXVDMA_RECTL
+{
+ int16_t left;
+ int16_t top;
+ uint16_t width;
+ uint16_t height;
+} VBOXVDMA_RECTL, *PVBOXVDMA_RECTL;
+
+typedef enum
+{
+ VBOXVDMA_PIXEL_FORMAT_UNKNOWN = 0,
+ VBOXVDMA_PIXEL_FORMAT_R8G8B8 = 20,
+ VBOXVDMA_PIXEL_FORMAT_A8R8G8B8 = 21,
+ VBOXVDMA_PIXEL_FORMAT_X8R8G8B8 = 22,
+ VBOXVDMA_PIXEL_FORMAT_R5G6B5 = 23,
+ VBOXVDMA_PIXEL_FORMAT_X1R5G5B5 = 24,
+ VBOXVDMA_PIXEL_FORMAT_A1R5G5B5 = 25,
+ VBOXVDMA_PIXEL_FORMAT_A4R4G4B4 = 26,
+ VBOXVDMA_PIXEL_FORMAT_R3G3B2 = 27,
+ VBOXVDMA_PIXEL_FORMAT_A8 = 28,
+ VBOXVDMA_PIXEL_FORMAT_A8R3G3B2 = 29,
+ VBOXVDMA_PIXEL_FORMAT_X4R4G4B4 = 30,
+ VBOXVDMA_PIXEL_FORMAT_A2B10G10R10 = 31,
+ VBOXVDMA_PIXEL_FORMAT_A8B8G8R8 = 32,
+ VBOXVDMA_PIXEL_FORMAT_X8B8G8R8 = 33,
+ VBOXVDMA_PIXEL_FORMAT_G16R16 = 34,
+ VBOXVDMA_PIXEL_FORMAT_A2R10G10B10 = 35,
+ VBOXVDMA_PIXEL_FORMAT_A16B16G16R16 = 36,
+ VBOXVDMA_PIXEL_FORMAT_A8P8 = 40,
+ VBOXVDMA_PIXEL_FORMAT_P8 = 41,
+ VBOXVDMA_PIXEL_FORMAT_L8 = 50,
+ VBOXVDMA_PIXEL_FORMAT_A8L8 = 51,
+ VBOXVDMA_PIXEL_FORMAT_A4L4 = 52,
+ VBOXVDMA_PIXEL_FORMAT_V8U8 = 60,
+ VBOXVDMA_PIXEL_FORMAT_L6V5U5 = 61,
+ VBOXVDMA_PIXEL_FORMAT_X8L8V8U8 = 62,
+ VBOXVDMA_PIXEL_FORMAT_Q8W8V8U8 = 63,
+ VBOXVDMA_PIXEL_FORMAT_V16U16 = 64,
+ VBOXVDMA_PIXEL_FORMAT_W11V11U10 = 65,
+ VBOXVDMA_PIXEL_FORMAT_A2W10V10U10 = 67
+} VBOXVDMA_PIXEL_FORMAT;
+
+typedef struct VBOXVDMA_SURF_DESC
+{
+ uint32_t width;
+ uint32_t height;
+ VBOXVDMA_PIXEL_FORMAT format;
+ uint32_t bpp;
+ uint32_t pitch;
+ uint32_t fFlags;
+} VBOXVDMA_SURF_DESC, *PVBOXVDMA_SURF_DESC;
+
+/*typedef uint64_t VBOXVDMAPHADDRESS;*/
+typedef uint64_t VBOXVDMASURFHANDLE;
+
+/* region specified as a rectangle, otherwize it is a size of memory pointed to by phys address */
+#define VBOXVDMAOPERAND_FLAGS_RECTL 0x1
+/* Surface handle is valid */
+#define VBOXVDMAOPERAND_FLAGS_PRIMARY 0x2
+/* address is offset in VRAM */
+#define VBOXVDMAOPERAND_FLAGS_VRAMOFFSET 0x4
+
+
+/* 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(_pCmd, _t) ( (_t*)(((uint8_t*)(_pCmd)) + sizeof (VBOXVDMACBUF_DR)) )
+#define VBOXVDMACBUF_DR_FROM_TAIL(_pCmd) ( (VBOXVDMACBUF_DR*)(((uint8_t*)(_pCmd)) - sizeof (VBOXVDMACBUF_DR)) )
+
+typedef struct VBOXVDMACMD
+{
+ VBOXVDMACMD_TYPE enmType;
+ uint32_t u32CmdSpecific;
+} VBOXVDMACMD, *PVBOXVDMACMD;
+
+#define VBOXVDMACMD_HEADER_SIZE() sizeof (VBOXVDMACMD)
+#define VBOXVDMACMD_SIZE_FROMBODYSIZE(_s) (VBOXVDMACMD_HEADER_SIZE() + (_s))
+#define VBOXVDMACMD_SIZE(_t) (VBOXVDMACMD_SIZE_FROMBODYSIZE(sizeof (_t)))
+#define VBOXVDMACMD_BODY(_pCmd, _t) ( (_t*)(((uint8_t*)(_pCmd)) + VBOXVDMACMD_HEADER_SIZE()) )
+#define VBOXVDMACMD_BODY_SIZE(_s) ( (_s) - VBOXVDMACMD_HEADER_SIZE() )
+#define VBOXVDMACMD_FROM_BODY(_pCmd) ( (VBOXVDMACMD*)(((uint8_t*)(_pCmd)) - VBOXVDMACMD_HEADER_SIZE()) )
+#define VBOXVDMACMD_BODY_FIELD_OFFSET(_ot, _t, _f) ( (_ot)(uintptr_t)( VBOXVDMACMD_BODY(0, uint8_t) + RT_OFFSETOF(_t, _f) ) )
+
+typedef struct VBOXVDMACMD_DMA_PRESENT_BLT
+{
+ VBOXVIDEOOFFSET offSrc;
+ VBOXVIDEOOFFSET offDst;
+ VBOXVDMA_SURF_DESC srcDesc;
+ VBOXVDMA_SURF_DESC dstDesc;
+ VBOXVDMA_RECTL srcRectl;
+ VBOXVDMA_RECTL dstRectl;
+ uint32_t u32Reserved;
+ uint32_t cDstSubRects;
+ VBOXVDMA_RECTL aDstSubRects[1];
+} VBOXVDMACMD_DMA_PRESENT_BLT, *PVBOXVDMACMD_DMA_PRESENT_BLT;
+
+typedef struct VBOXVDMACMD_DMA_PRESENT_SHADOW2PRIMARY
+{
+ VBOXVDMA_RECTL Rect;
+} VBOXVDMACMD_DMA_PRESENT_SHADOW2PRIMARY, *PVBOXVDMACMD_DMA_PRESENT_SHADOW2PRIMARY;
+
+
+#define VBOXVDMACMD_DMA_BPB_TRANSFER_F_SRC_VRAMOFFSET 0x00000001
+#define VBOXVDMACMD_DMA_BPB_TRANSFER_F_DST_VRAMOFFSET 0x00000002
+
+typedef struct VBOXVDMACMD_DMA_BPB_TRANSFER
+{
+ uint32_t cbTransferSize;
+ uint32_t fFlags;
+ union
+ {
+ uint64_t phBuf;
+ VBOXVIDEOOFFSET offVramBuf;
+ } Src;
+ union
+ {
+ uint64_t phBuf;
+ VBOXVIDEOOFFSET offVramBuf;
+ } Dst;
+} VBOXVDMACMD_DMA_BPB_TRANSFER, *PVBOXVDMACMD_DMA_BPB_TRANSFER;
+
+#define VBOXVDMACMD_SYSMEMEL_F_PAGELIST 0x00000001
+
+typedef struct VBOXVDMACMD_SYSMEMEL
+{
+ uint32_t cPages;
+ uint32_t fFlags;
+ uint64_t phBuf[1];
+} VBOXVDMACMD_SYSMEMEL, *PVBOXVDMACMD_SYSMEMEL;
+
+#define VBOXVDMACMD_SYSMEMEL_NEXT(_pEl) (((_pEl)->fFlags & VBOXVDMACMD_SYSMEMEL_F_PAGELIST) ? \
+ ((PVBOXVDMACMD_SYSMEMEL)(((uint8_t*)(_pEl))+RT_OFFSETOF(VBOXVDMACMD_SYSMEMEL, phBuf[(_pEl)->cPages]))) \
+ : \
+ ((_pEl)+1)
+
+#define VBOXVDMACMD_DMA_BPB_TRANSFER_VRAMSYS_SYS2VRAM 0x00000001
+
+typedef struct VBOXVDMACMD_DMA_BPB_TRANSFER_VRAMSYS
+{
+ uint32_t cTransferPages;
+ uint32_t fFlags;
+ VBOXVIDEOOFFSET offVramBuf;
+ VBOXVDMACMD_SYSMEMEL FirstEl;
+} VBOXVDMACMD_DMA_BPB_TRANSFER_VRAMSYS, *PVBOXVDMACMD_DMA_BPB_TRANSFER_VRAMSYS;
+
+typedef struct VBOXVDMACMD_DMA_BPB_FILL
+{
+ VBOXVIDEOOFFSET offSurf;
+ uint32_t cbFillSize;
+ uint32_t u32FillPattern;
+} VBOXVDMACMD_DMA_BPB_FILL, *PVBOXVDMACMD_DMA_BPB_FILL;
+
+#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;
+
+# pragma pack()
+#endif /* #ifdef VBOX_WITH_VDMA */
+
+#pragma pack(1)
+typedef struct VBOXVDMACMD_CHROMIUM_BUFFER
+{
+ VBOXVIDEOOFFSET offBuffer;
+ uint32_t cbBuffer;
+ uint32_t u32GuestData;
+ uint64_t u64GuestData;
+} VBOXVDMACMD_CHROMIUM_BUFFER, *PVBOXVDMACMD_CHROMIUM_BUFFER;
+
+typedef struct VBOXVDMACMD_CHROMIUM_CMD
+{
+ uint32_t cBuffers;
+ uint32_t u32Reserved;
+ VBOXVDMACMD_CHROMIUM_BUFFER aBuffers[1];
+} VBOXVDMACMD_CHROMIUM_CMD, *PVBOXVDMACMD_CHROMIUM_CMD;
+
+typedef enum
+{
+ VBOXVDMACMD_CHROMIUM_CTL_TYPE_UNKNOWN = 0,
+ VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP,
+ VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_BEGIN,
+ VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_END,
+ VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_MAINCB,
+ VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRCONNECT,
+ VBOXVDMACMD_CHROMIUM_CTL_TYPE_SIZEHACK = 0x7fffffff
+} VBOXVDMACMD_CHROMIUM_CTL_TYPE;
+
+typedef struct VBOXVDMACMD_CHROMIUM_CTL
+{
+ VBOXVDMACMD_CHROMIUM_CTL_TYPE enmType;
+ uint32_t cbCmd;
+} VBOXVDMACMD_CHROMIUM_CTL, *PVBOXVDMACMD_CHROMIUM_CTL;
+
+
+typedef struct PDMIDISPLAYVBVACALLBACKS *HCRHGSMICMDCOMPLETION;
+typedef DECLCALLBACK(int) FNCRHGSMICMDCOMPLETION(HCRHGSMICMDCOMPLETION hCompletion, PVBOXVDMACMD_CHROMIUM_CMD pCmd, int rc);
+typedef FNCRHGSMICMDCOMPLETION *PFNCRHGSMICMDCOMPLETION;
+
+/* tells whether 3D backend has some 3D overlay data displayed */
+typedef DECLCALLBACK(bool) FNCROGLHASDATA(void);
+typedef FNCROGLHASDATA *PFNCROGLHASDATA;
+
+/* same as PFNCROGLHASDATA, but for specific screen */
+typedef DECLCALLBACK(bool) FNCROGLHASDATAFORSCREEN(uint32_t i32ScreenID);
+typedef FNCROGLHASDATAFORSCREEN *PFNCROGLHASDATAFORSCREEN;
+
+/* callbacks chrogl gives to main */
+typedef struct CR_MAIN_INTERFACE
+{
+ PFNCROGLHASDATA pfnHasData;
+ PFNCROGLHASDATAFORSCREEN pfnHasDataForScreen;
+} CR_MAIN_INTERFACE;
+
+typedef struct VBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB
+{
+ VBOXVDMACMD_CHROMIUM_CTL Hdr;
+ /*in*/
+ HCRHGSMICMDCOMPLETION hCompletion;
+ PFNCRHGSMICMDCOMPLETION pfnCompletion;
+ /*out*/
+ CR_MAIN_INTERFACE MainInterface;
+} VBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB, *PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB;
+
+typedef struct VBOXCRCON_SERVER *HVBOXCRCON_SERVER;
+typedef struct PDMIDISPLAYVBVACALLBACKS* HVBOXCRCON_CLIENT;
+
+typedef struct VBOXCRCON_3DRGN_CLIENT* HVBOXCRCON_3DRGN_CLIENT;
+typedef struct VBOXCRCON_3DRGN_ASYNCCLIENT* HVBOXCRCON_3DRGN_ASYNCCLIENT;
+
+/* server callbacks */
+/* submit chromium cmd */
+typedef DECLCALLBACK(int) FNVBOXCRCON_SVR_CRCMD(HVBOXCRCON_SERVER hServer, PVBOXVDMACMD_CHROMIUM_CMD pCmd, uint32_t cbCmd);
+typedef FNVBOXCRCON_SVR_CRCMD *PFNVBOXCRCON_SVR_CRCMD;
+
+/* submit chromium control cmd */
+typedef DECLCALLBACK(int) FNVBOXCRCON_SVR_CRCTL(HVBOXCRCON_SERVER hServer, PVBOXVDMACMD_CHROMIUM_CTL pCtl, uint32_t cbCmd);
+typedef FNVBOXCRCON_SVR_CRCTL *PFNVBOXCRCON_SVR_CRCTL;
+
+/* request 3D data.
+ * The protocol is the following:
+ * 1. if there is no 3D data displayed on screen, returns VINF_EOF immediately w/o calling any PFNVBOXCRCON_3DRGN_XXX callbacks
+ * 2. otherwise calls PFNVBOXCRCON_3DRGN_ONSUBMIT, submits the "regions get" request to the CrOpenGL server to process it asynchronously and returns VINF_SUCCESS
+ * 2.a on "regions get" request processing calls PFNVBOXCRCON_3DRGN_BEGIN,
+ * 2.b then PFNVBOXCRCON_3DRGN_REPORT zero or more times for each 3D region,
+ * 2.c and then PFNVBOXCRCON_3DRGN_END
+ * 3. returns VERR_XXX code on failure
+ * */
+typedef DECLCALLBACK(int) FNVBOXCRCON_SVR_3DRGN_GET(HVBOXCRCON_SERVER hServer, HVBOXCRCON_3DRGN_CLIENT hRgnClient, uint32_t idScreen);
+typedef FNVBOXCRCON_SVR_3DRGN_GET *PFNVBOXCRCON_SVR_3DRGN_GET;
+
+/* 3D Regions Client callbacks */
+/* called from the PFNVBOXCRCON_SVR_3DRGN_GET callback in case server has 3D data and is going to process the request asynchronously,
+ * see comments for PFNVBOXCRCON_SVR_3DRGN_GET above */
+typedef DECLCALLBACK(int) FNVBOXCRCON_3DRGN_ONSUBMIT(HVBOXCRCON_3DRGN_CLIENT hRgnClient, uint32_t idScreen, HVBOXCRCON_3DRGN_ASYNCCLIENT *phRgnAsyncClient);
+typedef FNVBOXCRCON_3DRGN_ONSUBMIT *PFNVBOXCRCON_3DRGN_ONSUBMIT;
+
+/* called from the "regions get" command processing thread, to indicate that the "regions get" is started.
+ * see comments for PFNVBOXCRCON_SVR_3DRGN_GET above */
+typedef DECLCALLBACK(int) FNVBOXCRCON_3DRGN_BEGIN(HVBOXCRCON_3DRGN_ASYNCCLIENT hRgnAsyncClient, uint32_t idScreen);
+typedef FNVBOXCRCON_3DRGN_BEGIN *PFNVBOXCRCON_3DRGN_BEGIN;
+
+/* called from the "regions get" command processing thread, to report a 3D region.
+ * see comments for PFNVBOXCRCON_SVR_3DRGN_GET above */
+typedef DECLCALLBACK(int) FNVBOXCRCON_3DRGN_REPORT(HVBOXCRCON_3DRGN_ASYNCCLIENT hRgnAsyncClient, uint32_t idScreen, void *pvData, uint32_t cbStride, const RTRECT *pRect);
+typedef FNVBOXCRCON_3DRGN_REPORT *PFNVBOXCRCON_3DRGN_REPORT;
+
+/* called from the "regions get" command processing thread, to indicate that the "regions get" is completed.
+ * see comments for PFNVBOXCRCON_SVR_3DRGN_GET above */
+typedef DECLCALLBACK(int) FNVBOXCRCON_3DRGN_END(HVBOXCRCON_3DRGN_ASYNCCLIENT hRgnAsyncClient, uint32_t idScreen);
+typedef FNVBOXCRCON_3DRGN_END *PFNVBOXCRCON_3DRGN_END;
+
+
+/* client callbacks */
+/* complete chromium cmd */
+typedef DECLCALLBACK(int) FNVBOXCRCON_CLT_CRCTL_COMPLETE(HVBOXCRCON_CLIENT hClient, PVBOXVDMACMD_CHROMIUM_CTL pCtl, int rc);
+typedef FNVBOXCRCON_CLT_CRCTL_COMPLETE *PFNVBOXCRCON_CLT_CRCTL_COMPLETE;
+
+/* complete chromium control cmd */
+typedef DECLCALLBACK(int) FNVBOXCRCON_CLT_CRCMD_COMPLETE(HVBOXCRCON_CLIENT hClient, PVBOXVDMACMD_CHROMIUM_CMD pCmd, int rc);
+typedef FNVBOXCRCON_CLT_CRCMD_COMPLETE *PFNVBOXCRCON_CLT_CRCMD_COMPLETE;
+
+typedef struct VBOXCRCON_SERVER_CALLBACKS
+{
+ HVBOXCRCON_SERVER hServer;
+ PFNVBOXCRCON_SVR_CRCMD pfnCrCmd;
+ PFNVBOXCRCON_SVR_CRCTL pfnCrCtl;
+ PFNVBOXCRCON_SVR_3DRGN_GET pfn3DRgnGet;
+} VBOXCRCON_SERVER_CALLBACKS, *PVBOXCRCON_SERVER_CALLBACKS;
+
+typedef struct VBOXCRCON_CLIENT_CALLBACKS
+{
+ HVBOXCRCON_CLIENT hClient;
+ PFNVBOXCRCON_CLT_CRCMD_COMPLETE pfnCrCmdComplete;
+ PFNVBOXCRCON_CLT_CRCTL_COMPLETE pfnCrCtlComplete;
+ PFNVBOXCRCON_3DRGN_ONSUBMIT pfn3DRgnOnSubmit;
+ PFNVBOXCRCON_3DRGN_BEGIN pfn3DRgnBegin;
+ PFNVBOXCRCON_3DRGN_REPORT pfn3DRgnReport;
+ PFNVBOXCRCON_3DRGN_END pfn3DRgnEnd;
+} VBOXCRCON_CLIENT_CALLBACKS, *PVBOXCRCON_CLIENT_CALLBACKS;
+
+/* issued by Main to establish connection between Main and CrOpenGL service */
+typedef struct VBOXVDMACMD_CHROMIUM_CTL_CRCONNECT
+{
+ VBOXVDMACMD_CHROMIUM_CTL Hdr;
+ /*input (filled by Client) :*/
+ /*class VMMDev*/void *pVMMDev;
+ VBOXCRCON_CLIENT_CALLBACKS ClientCallbacks;
+ /*output (filled by Server) :*/
+ VBOXCRCON_SERVER_CALLBACKS ServerCallbacks;
+} VBOXVDMACMD_CHROMIUM_CTL_CRCONNECT, *PVBOXVDMACMD_CHROMIUM_CTL_CRCONNECT;
+
+/* ring command buffer dr */
+#define VBOXCMDVBVA_STATE_SUBMITTED 1
+#define VBOXCMDVBVA_STATE_CANCELLED 2
+#define VBOXCMDVBVA_STATE_IN_PROGRESS 3
+/* the "completed" state is signalled via the ring buffer values */
+
+/* CrHgsmi command */
+#define VBOXCMDVBVA_OPTYPE_CRCMD 1
+/* blit command that does blitting of allocations identified by VRAM offset or host id
+ * for VRAM-offset ones the size and format are same as primary */
+#define VBOXCMDVBVA_OPTYPE_BLT 2
+/* flip */
+#define VBOXCMDVBVA_OPTYPE_FLIP 3
+/* ColorFill */
+#define VBOXCMDVBVA_OPTYPE_CLRFILL 4
+/* allocation paging transfer request */
+#define VBOXCMDVBVA_OPTYPE_PAGING_TRANSFER 5
+/* allocation paging fill request */
+#define VBOXCMDVBVA_OPTYPE_PAGING_FILL 6
+/* same as VBOXCMDVBVA_OPTYPE_NOP, but contains VBOXCMDVBVA_HDR data */
+#define VBOXCMDVBVA_OPTYPE_NOPCMD 7
+/* actual command is stored in guest system memory */
+#define VBOXCMDVBVA_OPTYPE_SYSMEMCMD 8
+/* complex command - i.e. can contain multiple commands
+ * i.e. the VBOXCMDVBVA_OPTYPE_COMPLEXCMD VBOXCMDVBVA_HDR is followed
+ * by one or more VBOXCMDVBVA_HDR commands.
+ * Each command's size is specified in it's VBOXCMDVBVA_HDR's u32FenceID field */
+#define VBOXCMDVBVA_OPTYPE_COMPLEXCMD 9
+
+/* nop - is a one-bit command. The buffer size to skip is determined by VBVA buffer size */
+#define VBOXCMDVBVA_OPTYPE_NOP 0x80
+
+/* u8Flags flags */
+/* transfer from RAM to Allocation */
+#define VBOXCMDVBVA_OPF_PAGING_TRANSFER_IN 0x80
+
+#define VBOXCMDVBVA_OPF_BLT_TYPE_SAMEDIM_A8R8G8B8 0
+#define VBOXCMDVBVA_OPF_BLT_TYPE_GENERIC_A8R8G8B8 1
+#define VBOXCMDVBVA_OPF_BLT_TYPE_OFFPRIMSZFMT_OR_ID 2
+
+#define VBOXCMDVBVA_OPF_BLT_TYPE_MASK 3
+
+
+#define VBOXCMDVBVA_OPF_CLRFILL_TYPE_GENERIC_A8R8G8B8 0
+
+#define VBOXCMDVBVA_OPF_CLRFILL_TYPE_MASK 1
+
+
+/* blit direction is from first operand to second */
+#define VBOXCMDVBVA_OPF_BLT_DIR_IN_2 0x10
+/* operand 1 contains host id */
+#define VBOXCMDVBVA_OPF_OPERAND1_ISID 0x20
+/* operand 2 contains host id */
+#define VBOXCMDVBVA_OPF_OPERAND2_ISID 0x40
+/* primary hint id is src */
+#define VBOXCMDVBVA_OPF_PRIMARY_HINT_SRC 0x80
+
+/* trying to make the header as small as possible,
+ * we'd have pretty few op codes actually, so 8bit is quite enough,
+ * we will be able to extend it in any way. */
+typedef struct VBOXCMDVBVA_HDR
+{
+ /* one VBOXCMDVBVA_OPTYPE_XXX, except NOP, see comments above */
+ uint8_t u8OpCode;
+ /* command-specific
+ * VBOXCMDVBVA_OPTYPE_CRCMD - must be null
+ * VBOXCMDVBVA_OPTYPE_BLT - OR-ed VBOXCMDVBVA_OPF_ALLOC_XXX flags
+ * VBOXCMDVBVA_OPTYPE_PAGING_TRANSFER - must be null
+ * VBOXCMDVBVA_OPTYPE_PAGING_FILL - must be null
+ * VBOXCMDVBVA_OPTYPE_NOPCMD - must be null
+ * VBOXCMDVBVA_OPTYPE_NOP - not applicable (as the entire VBOXCMDVBVA_HDR is not valid) */
+ uint8_t u8Flags;
+ /* one of VBOXCMDVBVA_STATE_XXX*/
+ volatile uint8_t u8State;
+ union
+ {
+ /* result, 0 on success, otherwise contains the failure code TBD */
+ int8_t i8Result;
+ uint8_t u8PrimaryID;
+ } u;
+ union
+ {
+ /* complex command (VBOXCMDVBVA_OPTYPE_COMPLEXCMD) element data */
+ struct
+ {
+ /* command length */
+ uint16_t u16CbCmdHost;
+ /* guest-specific data, host expects it to be NULL */
+ uint16_t u16CbCmdGuest;
+ } complexCmdEl;
+ /* DXGK DDI fence ID */
+ uint32_t u32FenceID;
+ } u2;
+} VBOXCMDVBVA_HDR;
+
+typedef uint32_t VBOXCMDVBVAOFFSET;
+typedef uint64_t VBOXCMDVBVAPHADDR;
+typedef uint32_t VBOXCMDVBVAPAGEIDX;
+
+typedef struct VBOXCMDVBVA_CRCMD_BUFFER
+{
+ uint32_t cbBuffer;
+ VBOXCMDVBVAOFFSET offBuffer;
+} VBOXCMDVBVA_CRCMD_BUFFER;
+
+typedef struct VBOXCMDVBVA_CRCMD_CMD
+{
+ uint32_t cBuffers;
+ VBOXCMDVBVA_CRCMD_BUFFER aBuffers[1];
+} VBOXCMDVBVA_CRCMD_CMD;
+
+typedef struct VBOXCMDVBVA_CRCMD
+{
+ VBOXCMDVBVA_HDR Hdr;
+ VBOXCMDVBVA_CRCMD_CMD Cmd;
+} VBOXCMDVBVA_CRCMD;
+
+typedef struct VBOXCMDVBVA_ALLOCINFO
+{
+ union
+ {
+ VBOXCMDVBVAOFFSET offVRAM;
+ uint32_t id;
+ } u;
+} VBOXCMDVBVA_ALLOCINFO;
+
+typedef struct VBOXCMDVBVA_ALLOCDESC
+{
+ VBOXCMDVBVA_ALLOCINFO Info;
+ uint16_t u16Width;
+ uint16_t u16Height;
+} VBOXCMDVBVA_ALLOCDESC;
+
+typedef struct VBOXCMDVBVA_RECT
+{
+ /** Coordinates of affected rectangle. */
+ int16_t xLeft;
+ int16_t yTop;
+ int16_t xRight;
+ int16_t yBottom;
+} VBOXCMDVBVA_RECT;
+
+typedef struct VBOXCMDVBVA_POINT
+{
+ int16_t x;
+ int16_t y;
+} VBOXCMDVBVA_POINT;
+
+typedef struct VBOXCMDVBVA_BLT_HDR
+{
+ VBOXCMDVBVA_HDR Hdr;
+ VBOXCMDVBVA_POINT Pos;
+} VBOXCMDVBVA_BLT_HDR;
+
+typedef struct VBOXCMDVBVA_BLT_PRIMARY
+{
+ VBOXCMDVBVA_BLT_HDR Hdr;
+ VBOXCMDVBVA_ALLOCINFO alloc;
+ /* the rects count is determined from the command size */
+ VBOXCMDVBVA_RECT aRects[1];
+} VBOXCMDVBVA_BLT_PRIMARY;
+
+typedef struct VBOXCMDVBVA_BLT_PRIMARY_GENERIC_A8R8G8B8
+{
+ VBOXCMDVBVA_BLT_HDR Hdr;
+ VBOXCMDVBVA_ALLOCDESC alloc;
+ /* the rects count is determined from the command size */
+ VBOXCMDVBVA_RECT aRects[1];
+} VBOXCMDVBVA_BLT_PRIMARY_GENERIC_A8R8G8B8;
+
+typedef struct VBOXCMDVBVA_BLT_OFFPRIMSZFMT_OR_ID
+{
+ VBOXCMDVBVA_BLT_HDR Hdr;
+ VBOXCMDVBVA_ALLOCINFO alloc;
+ uint32_t id;
+ /* the rects count is determined from the command size */
+ VBOXCMDVBVA_RECT aRects[1];
+} VBOXCMDVBVA_BLT_OFFPRIMSZFMT_OR_ID;
+
+typedef struct VBOXCMDVBVA_BLT_SAMEDIM_A8R8G8B8
+{
+ VBOXCMDVBVA_BLT_HDR Hdr;
+ VBOXCMDVBVA_ALLOCDESC alloc1;
+ VBOXCMDVBVA_ALLOCINFO info2;
+ /* the rects count is determined from the command size */
+ VBOXCMDVBVA_RECT aRects[1];
+} VBOXCMDVBVA_BLT_SAMEDIM_A8R8G8B8;
+
+typedef struct VBOXCMDVBVA_BLT_GENERIC_A8R8G8B8
+{
+ VBOXCMDVBVA_BLT_HDR Hdr;
+ VBOXCMDVBVA_ALLOCDESC alloc1;
+ VBOXCMDVBVA_ALLOCDESC alloc2;
+ /* the rects count is determined from the command size */
+ VBOXCMDVBVA_RECT aRects[1];
+} VBOXCMDVBVA_BLT_GENERIC_A8R8G8B8;
+
+#define VBOXCMDVBVA_SIZEOF_BLTSTRUCT_MAX (sizeof (VBOXCMDVBVA_BLT_GENERIC_A8R8G8B8))
+
+typedef struct VBOXCMDVBVA_FLIP
+{
+ VBOXCMDVBVA_HDR Hdr;
+ VBOXCMDVBVA_ALLOCINFO src;
+ VBOXCMDVBVA_RECT aRects[1];
+} VBOXCMDVBVA_FLIP;
+
+#define VBOXCMDVBVA_SIZEOF_FLIPSTRUCT_MIN (RT_OFFSETOF(VBOXCMDVBVA_FLIP, aRects))
+
+typedef struct VBOXCMDVBVA_CLRFILL_HDR
+{
+ VBOXCMDVBVA_HDR Hdr;
+ uint32_t u32Color;
+} VBOXCMDVBVA_CLRFILL_HDR;
+
+typedef struct VBOXCMDVBVA_CLRFILL_PRIMARY
+{
+ VBOXCMDVBVA_CLRFILL_HDR Hdr;
+ VBOXCMDVBVA_RECT aRects[1];
+} VBOXCMDVBVA_CLRFILL_PRIMARY;
+
+typedef struct VBOXCMDVBVA_CLRFILL_GENERIC_A8R8G8B8
+{
+ VBOXCMDVBVA_CLRFILL_HDR Hdr;
+ VBOXCMDVBVA_ALLOCDESC dst;
+ VBOXCMDVBVA_RECT aRects[1];
+} VBOXCMDVBVA_CLRFILL_GENERIC_A8R8G8B8;
+
+#define VBOXCMDVBVA_SIZEOF_CLRFILLSTRUCT_MAX (sizeof (VBOXCMDVBVA_CLRFILL_GENERIC_A8R8G8B8))
+
+#if 0
+#define VBOXCMDVBVA_SYSMEMEL_CPAGES_MAX 0x1000
+
+typedef struct VBOXCMDVBVA_SYSMEMEL
+{
+ uint32_t cPagesAfterFirst : 12;
+ uint32_t iPage1 : 20;
+ uint32_t iPage2;
+} VBOXCMDVBVA_SYSMEMEL;
+#endif
+
+typedef struct VBOXCMDVBVA_PAGING_TRANSFER_DATA
+{
+ /* for now can only contain offVRAM.
+ * paging transfer can NOT be initiated for allocations having host 3D object (hostID) associated */
+ VBOXCMDVBVA_ALLOCINFO Alloc;
+ VBOXCMDVBVAPAGEIDX aPageNumbers[1];
+} VBOXCMDVBVA_PAGING_TRANSFER_DATA;
+
+typedef struct VBOXCMDVBVA_PAGING_TRANSFER
+{
+ VBOXCMDVBVA_HDR Hdr;
+ VBOXCMDVBVA_PAGING_TRANSFER_DATA Data;
+} VBOXCMDVBVA_PAGING_TRANSFER;
+
+typedef struct VBOXCMDVBVA_PAGING_FILL
+{
+ VBOXCMDVBVA_HDR Hdr;
+ uint32_t u32CbFill;
+ uint32_t u32Pattern;
+ /* paging transfer can NOT be initiated for allocations having host 3D object (hostID) associated */
+ VBOXCMDVBVAOFFSET offVRAM;
+} VBOXCMDVBVA_PAGING_FILL;
+
+typedef struct VBOXCMDVBVA_SYSMEMCMD
+{
+ VBOXCMDVBVA_HDR Hdr;
+ VBOXCMDVBVAPHADDR phCmd;
+} VBOXCMDVBVA_SYSMEMCMD;
+
+#define VBOXCMDVBVACTL_TYPE_ENABLE 1
+#define VBOXCMDVBVACTL_TYPE_3DCTL 2
+#define VBOXCMDVBVACTL_TYPE_RESIZE 3
+
+typedef struct VBOXCMDVBVA_CTL
+{
+ uint32_t u32Type;
+ int32_t i32Result;
+} VBOXCMDVBVA_CTL;
+
+typedef struct VBOXCMDVBVA_CTL_ENABLE
+{
+ VBOXCMDVBVA_CTL Hdr;
+ VBVAENABLE Enable;
+} VBOXCMDVBVA_CTL_ENABLE;
+
+#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)]
+
+typedef struct VBOXCMDVBVA_RESIZE_ENTRY
+{
+ VBVAINFOSCREEN Screen;
+ VBOXCMDVBVA_SCREENMAP_DECL(uint32_t, aTargetMap);
+} VBOXCMDVBVA_RESIZE_ENTRY;
+
+typedef struct VBOXCMDVBVA_RESIZE
+{
+ VBOXCMDVBVA_RESIZE_ENTRY aEntries[1];
+} VBOXCMDVBVA_RESIZE;
+
+typedef struct VBOXCMDVBVA_CTL_RESIZE
+{
+ VBOXCMDVBVA_CTL Hdr;
+ VBOXCMDVBVA_RESIZE Resize;
+} VBOXCMDVBVA_CTL_RESIZE;
+
+#define VBOXCMDVBVA3DCTL_TYPE_CONNECT 1
+#define VBOXCMDVBVA3DCTL_TYPE_DISCONNECT 2
+#define VBOXCMDVBVA3DCTL_TYPE_CMD 3
+
+typedef struct VBOXCMDVBVA_3DCTL
+{
+ uint32_t u32Type;
+ uint32_t u32CmdClientId;
+} VBOXCMDVBVA_3DCTL;
+
+typedef struct VBOXCMDVBVA_3DCTL_CONNECT
+{
+ VBOXCMDVBVA_3DCTL Hdr;
+ uint32_t u32MajorVersion;
+ uint32_t u32MinorVersion;
+ uint64_t u64Pid;
+} VBOXCMDVBVA_3DCTL_CONNECT;
+
+typedef struct VBOXCMDVBVA_3DCTL_CMD
+{
+ VBOXCMDVBVA_3DCTL Hdr;
+ VBOXCMDVBVA_HDR Cmd;
+} VBOXCMDVBVA_3DCTL_CMD;
+
+typedef struct VBOXCMDVBVA_CTL_3DCTL_CMD
+{
+ VBOXCMDVBVA_CTL Hdr;
+ VBOXCMDVBVA_3DCTL_CMD Cmd;
+} VBOXCMDVBVA_CTL_3DCTL_CMD;
+
+typedef struct VBOXCMDVBVA_CTL_3DCTL_CONNECT
+{
+ VBOXCMDVBVA_CTL Hdr;
+ VBOXCMDVBVA_3DCTL_CONNECT Connect;
+} VBOXCMDVBVA_CTL_3DCTL_CONNECT;
+
+typedef struct VBOXCMDVBVA_CTL_3DCTL
+{
+ VBOXCMDVBVA_CTL Hdr;
+ VBOXCMDVBVA_3DCTL Ctl;
+} VBOXCMDVBVA_CTL_3DCTL;
+
+#pragma pack()
+
+
+#ifdef VBOXVDMA_WITH_VBVA
+# pragma pack(1)
+
+typedef struct VBOXVDMAVBVACMD
+{
+ HGSMIOFFSET offCmd;
+} VBOXVDMAVBVACMD;
+
+#pragma pack()
+#endif
+
+#endif
--- /dev/null
+/** @file
+ * VBox Host Guest Shared Memory Interface (HGSMI).
+ * OS-independent guest structures.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+#ifndef ___VBox_VBoxVideoGuest_h___
+#define ___VBox_VBoxVideoGuest_h___
+
+#include <VBox/HGSMI/HGSMI.h>
+#include <VBox/HGSMI/HGSMIChSetup.h>
+#include <VBox/VBoxVideo.h>
+
+#ifdef VBOX_XPDM_MINIPORT
+# include <iprt/nt/miniport.h>
+# include <ntddvdeo.h> /* sdk, clean */
+# include <iprt/nt/Video.h>
+#elif defined VBOX_GUESTR3XORGMOD
+# include <compiler.h>
+#else
+# include <iprt/asm-amd64-x86.h>
+#endif
+
+#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;
+
+
+/**
+ * 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 Helper functions
+ * @{ */
+/** Write an 8-bit value to an I/O port. */
+DECLINLINE(void) VBoxVideoCmnPortWriteUchar(RTIOPORT Port, uint8_t Value)
+{
+#ifdef VBOX_XPDM_MINIPORT
+ VideoPortWritePortUchar((PUCHAR)Port, Value);
+#elif defined VBOX_GUESTR3XORGMOD
+ outb(Port, Value);
+#else /** @todo make these explicit */
+ ASMOutU8(Port, Value);
+#endif
+}
+
+/** Write a 16-bit value to an I/O port. */
+DECLINLINE(void) VBoxVideoCmnPortWriteUshort(RTIOPORT Port, uint16_t Value)
+{
+#ifdef VBOX_XPDM_MINIPORT
+ VideoPortWritePortUshort((PUSHORT)Port,Value);
+#elif defined VBOX_GUESTR3XORGMOD
+ outw(Port, Value);
+#else
+ ASMOutU16(Port, Value);
+#endif
+}
+
+/** Write a 32-bit value to an I/O port. */
+DECLINLINE(void) VBoxVideoCmnPortWriteUlong(RTIOPORT Port, uint32_t Value)
+{
+#ifdef VBOX_XPDM_MINIPORT
+ VideoPortWritePortUlong((PULONG)Port,Value);
+#elif defined VBOX_GUESTR3XORGMOD
+ outl(Port, Value);
+#else
+ ASMOutU32(Port, Value);
+#endif
+}
+
+/** Read an 8-bit value from an I/O port. */
+DECLINLINE(uint8_t) VBoxVideoCmnPortReadUchar(RTIOPORT Port)
+{
+#ifdef VBOX_XPDM_MINIPORT
+ return VideoPortReadPortUchar((PUCHAR)Port);
+#elif defined VBOX_GUESTR3XORGMOD
+ return inb(Port);
+#else
+ return ASMInU8(Port);
+#endif
+}
+
+/** Read a 16-bit value from an I/O port. */
+DECLINLINE(uint16_t) VBoxVideoCmnPortReadUshort(RTIOPORT Port)
+{
+#ifdef VBOX_XPDM_MINIPORT
+ return VideoPortReadPortUshort((PUSHORT)Port);
+#elif defined VBOX_GUESTR3XORGMOD
+ return inw(Port);
+#else
+ return ASMInU16(Port);
+#endif
+}
+
+/** Read a 32-bit value from an I/O port. */
+DECLINLINE(uint32_t) VBoxVideoCmnPortReadUlong(RTIOPORT Port)
+{
+#ifdef VBOX_XPDM_MINIPORT
+ return VideoPortReadPortUlong((PULONG)Port);
+#elif defined VBOX_GUESTR3XORGMOD
+ return inl(Port);
+#else
+ return ASMInU32(Port);
+#endif
+}
+
+/** @} */
+
+/** @name Base HGSMI APIs
+ * @{ */
+
+/** Acknowlege an IRQ. */
+DECLINLINE(void) VBoxHGSMIClearIrq(PHGSMIHOSTCOMMANDCONTEXT pCtx)
+{
+ VBoxVideoCmnPortWriteUlong(pCtx->port, HGSMIOFFSET_VOID);
+}
+
+DECLHIDDEN(void) VBoxHGSMIHostCmdComplete(PHGSMIHOSTCOMMANDCONTEXT pCtx,
+ void *pvMem);
+DECLHIDDEN(void) VBoxHGSMIProcessHostQueue(PHGSMIHOSTCOMMANDCONTEXT pCtx);
+DECLHIDDEN(bool) VBoxHGSMIIsSupported(void);
+DECLHIDDEN(void *) VBoxHGSMIBufferAlloc(PHGSMIGUESTCOMMANDCONTEXT pCtx,
+ HGSMISIZE cbData,
+ uint8_t u8Ch,
+ uint16_t u16Op);
+DECLHIDDEN(void) VBoxHGSMIBufferFree(PHGSMIGUESTCOMMANDCONTEXT pCtx,
+ void *pvBuffer);
+DECLHIDDEN(int) VBoxHGSMIBufferSubmit(PHGSMIGUESTCOMMANDCONTEXT pCtx,
+ void *pvBuffer);
+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);
+/** @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) VBoxHGSMIGetHostAreaMapping(PHGSMIGUESTCOMMANDCONTEXT pCtx,
+ uint32_t cbVRAM,
+ uint32_t offVRAMBaseMapping,
+ uint32_t *poffVRAMHostArea,
+ uint32_t *pcbHostArea);
+DECLHIDDEN(void) VBoxHGSMISetupHostContext(PHGSMIHOSTCOMMANDCONTEXT pCtx,
+ void *pvBaseMapping,
+ uint32_t offHostFlags,
+ void *pvHostAreaMapping,
+ uint32_t offVRAMHostArea,
+ uint32_t cbHostArea);
+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(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 DECLCALLBACK(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
+
--- /dev/null
+/** @file
+ * Virtual Device for Guest <-> VMM/Host communication (ADD,DEV).
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___VBox_VMMDev_h
+#define ___VBox_VMMDev_h
+
+#include <VBox/cdefs.h>
+#include <VBox/param.h> /* for the PCI IDs. */
+#include <VBox/types.h>
+#include <VBox/err.h>
+#include <VBox/ostypes.h>
+#include <VBox/VMMDev2.h>
+#include <iprt/assert.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
+
+
+/** @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)
+/** @} */
+
+
+/** @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. */
+#define VMMDEV_MAX_HGCM_PARMS 1024
+/** Maximum total size of hgcm buffers in one call. */
+#define VMMDEV_MAX_HGCM_DATA_SIZE UINT32_C(0x7FFFFFFF)
+
+/**
+ * VMMDev request types.
+ * @note when updating this, adjust vmmdevGetRequestSize() as well
+ */
+typedef enum
+{
+ 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 */
+#ifdef VBOX_WITH_HGCM
+ VMMDevReq_HGCMConnect = 60,
+ VMMDevReq_HGCMDisconnect = 61,
+#ifdef VBOX_WITH_64_BITS_GUESTS
+ VMMDevReq_HGCMCall32 = 62,
+ VMMDevReq_HGCMCall64 = 63,
+#else
+ VMMDevReq_HGCMCall = 62,
+#endif /* VBOX_WITH_64_BITS_GUESTS */
+ 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_SizeHack = 0x7fffffff
+} VMMDevRequestType;
+
+#ifdef VBOX_WITH_64_BITS_GUESTS
+/*
+ * Constants and structures are redefined for the guest.
+ *
+ * Host code MUST always use either *32 or *64 variant explicitely.
+ * Host source code will use VBOX_HGCM_HOST_CODE define to catch undefined
+ * data types and constants.
+ *
+ * This redefinition means that the new additions builds will use
+ * the *64 or *32 variants depending on the current architecture bit count (ARCH_BITS).
+ */
+# ifndef VBOX_HGCM_HOST_CODE
+# if ARCH_BITS == 64
+# define VMMDevReq_HGCMCall VMMDevReq_HGCMCall64
+# elif ARCH_BITS == 32
+# define VMMDevReq_HGCMCall VMMDevReq_HGCMCall32
+# else
+# error "Unsupported ARCH_BITS"
+# endif
+# endif /* !VBOX_HGCM_HOST_CODE */
+#endif /* VBOX_WITH_64_BITS_GUESTS */
+
+/** Version of VMMDevRequestHeader structure. */
+#define VMMDEV_REQUEST_HEADER_VERSION (0x10001)
+
+
+/**
+ * Generic VMMDev request header.
+ */
+typedef struct
+{
+ /** IN: Size of the structure in bytes (including body). */
+ uint32_t size;
+ /** IN: Version of the structure. */
+ uint32_t version;
+ /** IN: Type of the request. */
+ VMMDevRequestType requestType;
+ /** OUT: Return code. */
+ int32_t rc;
+ /** Reserved field no.1. MBZ. */
+ uint32_t reserved1;
+ /** Reserved field no.2. MBZ. */
+ uint32_t reserved2;
+} VMMDevRequestHeader;
+AssertCompileSize(VMMDevRequestHeader, 24);
+
+
+/**
+ * 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 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 mask of all VMMDEV_MOUSE_* flags */
+#define VMMDEV_MOUSE_MASK UINT32_C(0x0000007f)
+/** 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)
+/** 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)
+/** @} */
+
+/** @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. */
+ 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_OFFSETOF(VMMDevReqMousePointer, pointerData);
+ size_t cbMask = (width + 7) / 8 * height;
+ size_t cbArgb = width * height * 4;
+ return RT_MAX(cbBase + ((cbMask + 3) & ~3) + cbArgb,
+ sizeof(VMMDevReqMousePointer));
+}
+
+/** @name VMMDevReqMousePointer::fFlags
+ * @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)
+/** @} */
+
+
+/**
+ * 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 VMMDevReqHostVersion::features
+ * @{ */
+/** Physical page lists are supported by HGCM. */
+#define VMMDEV_HVF_HGCM_PHYS_PAGE_LIST RT_BIT(0)
+/** @} */
+
+
+/**
+ * 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);
+
+/** @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)
+/** @} */
+
+
+/**
+ * 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, currently unused. */
+ 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);
+
+/**
+ * Guest information report, version 2.
+ *
+ * Used by VMMDevReq_ReportGuestInfo2.
+ */
+typedef struct
+{
+ /** Header. */
+ VMMDevRequestHeader header;
+ /** Guest information. */
+ VBoxGuestInfo2 guestInfo;
+} VMMDevReportGuestInfo2;
+AssertCompileSize(VMMDevReportGuestInfo2, 24+144);
+
+
+/**
+ * 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_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 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);
+
+
+/**
+ * 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);
+
+
+/**
+ * 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);
+
+/** @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)
+/** @} */
+
+
+/**
+ * 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);
+
+
+/**
+ * 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);
+
+/**
+ * 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);
+
+
+/**
+ * Shared region description
+ */
+typedef struct VMMDEVSHAREDREGIONDESC
+{
+ RTGCPTR64 GCRegionAddr;
+ uint32_t cbRegion;
+ uint32_t u32Alignment;
+} VMMDEVSHAREDREGIONDESC;
+AssertCompileSize(VMMDEVSHAREDREGIONDESC, 16);
+
+#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);
+
+
+
+#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 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 */
+ VMMDevHGCMParmType_LinAddr_Locked_In = 8, /**< Locked In (read; host<-guest) */
+ VMMDevHGCMParmType_LinAddr_Locked_Out = 9, /**< Locked Out (write; host->guest) */
+ VMMDevHGCMParmType_PageList = 10, /**< Physical addresses of locked pages for a buffer. */
+ VMMDevHGCMParmType_SizeHack = 0x7fffffff
+} HGCMFunctionParameterType;
+AssertCompileSize(HGCMFunctionParameterType, 4);
+
+# ifdef VBOX_WITH_64_BITS_GUESTS
+/**
+ * HGCM function parameter, 32-bit client.
+ */
+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 size; /**< Size of the buffer described by the page list. */
+ uint32_t offset; /**< Relative to the request header, valid if size != 0. */
+ } PageList;
+ } 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)
+ {
+ 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 *pu64)
+ {
+ if (type == VMMDevHGCMParmType_64bit)
+ {
+ *pu64 = u.value64;
+ return VINF_SUCCESS;
+ }
+ return VERR_INVALID_PARAMETER;
+ }
+
+ void SetPtr(void *pv, uint32_t cb)
+ {
+ type = VMMDevHGCMParmType_LinAddr;
+ u.Pointer.size = cb;
+ u.Pointer.u.linearAddr = (RTGCPTR32)(uintptr_t)pv;
+ }
+# endif /* __cplusplus */
+} HGCMFunctionParameter32;
+AssertCompileSize(HGCMFunctionParameter32, 4+8);
+
+/**
+ * HGCM function parameter, 64-bit client.
+ */
+typedef struct
+{
+ HGCMFunctionParameterType type;
+ union
+ {
+ uint32_t value32;
+ uint64_t value64;
+ struct
+ {
+ uint32_t size;
+
+ union
+ {
+ RTGCPHYS64 physAddr;
+ RTGCPTR64 linearAddr;
+ } u;
+ } Pointer;
+ 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;
+ } 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)
+ {
+ 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 *pu64)
+ {
+ if (type == VMMDevHGCMParmType_64bit)
+ {
+ *pu64 = u.value64;
+ return VINF_SUCCESS;
+ }
+ return VERR_INVALID_PARAMETER;
+ }
+
+ void SetPtr(void *pv, uint32_t cb)
+ {
+ type = VMMDevHGCMParmType_LinAddr;
+ u.Pointer.size = cb;
+ u.Pointer.u.linearAddr = (uintptr_t)pv;
+ }
+# endif /** __cplusplus */
+} HGCMFunctionParameter64;
+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
+# 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?
+ */
+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 size; /**< Size of the buffer described by the page list. */
+ uint32_t offset; /**< Relative to the request header, valid if size != 0. */
+ } PageList;
+ } 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)
+ {
+ 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 *pu64)
+ {
+ if (type == VMMDevHGCMParmType_64bit)
+ {
+ *pu64 = u.value64;
+ return VINF_SUCCESS;
+ }
+ return VERR_INVALID_PARAMETER;
+ }
+
+ void SetPtr(void *pv, uint32_t cb)
+ {
+ type = VMMDevHGCMParmType_LinAddr;
+ u.Pointer.size = cb;
+ u.Pointer.u.linearAddr = (uintptr_t)pv;
+ }
+# endif /* __cplusplus */
+} HGCMFunctionParameter;
+AssertCompileSize(HGCMFunctionParameter, 4+8);
+# endif /* !VBOX_WITH_64_BITS_GUESTS */
+
+/**
+ * HGCM call request structure.
+ *
+ * Used by VMMDevReq_HGCMCall, 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)
+/** Macro for validating that the specified flags are valid. */
+#define VBOX_HGCM_F_PARM_ARE_VALID(fFlags) \
+ ( (fFlags) > VBOX_HGCM_F_PARM_DIRECTION_NONE \
+ && (fFlags) < VBOX_HGCM_F_PARM_DIRECTION_BOTH )
+/** @} */
+
+/**
+ * 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_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_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);
+#ifdef VBOX_WITH_64_BITS_GUESTS
+ case VMMDevReq_HGCMCall32:
+ return sizeof(VMMDevHGCMCall);
+ case VMMDevReq_HGCMCall64:
+ return sizeof(VMMDevHGCMCall);
+#else
+ case VMMDevReq_HGCMCall:
+ return sizeof(VMMDevHGCMCall);
+#endif /* VBOX_WITH_64_BITS_GUESTS */
+ 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);
+ 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->reserved2 = 0;
+ return VINF_SUCCESS;
+}
+
+/** @} */
+
+
+/**
+ * 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);
+
+
+/**
+ * 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[VBVA_RING_BUFFER_SIZE];
+
+ /** The queue of record descriptions. */
+ VBVARECORD aRecords[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)
+
+/** @} */
+
+RT_C_DECLS_END
+#pragma pack()
+
+#endif
+
--- /dev/null
+/** @file
+ * Virtual Device for Guest <-> VMM/Host communication, Mixed Up Mess. (ADD,DEV)
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___VBox_VMMDev2_h
+#define ___VBox_VMMDev2_h
+
+#include <iprt/assert.h>
+
+
+/** @addtogroup grp_vmmdev
+ * @{
+ */
+
+
+/**
+ * Seamless mode.
+ *
+ * Used by VbglR3SeamlessWaitEvent
+ *
+ * @ingroup grp_vmmdev_req
+ *
+ * @todo DARN! DARN! DARN! Who forgot to do the 32-bit hack here???
+ * FIXME! XXX!
+ *
+ * We will now have to carefully check how our compilers have treated this
+ * flag. If any are compressing it into a byte type, we'll have to check
+ * how the request memory is initialized. If we are 104% sure it's ok to
+ * expand it, we'll expand it. If not, we must redefine the field to a
+ * uint8_t and a 3 byte padding.
+ */
+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. */
+} VMMDevSeamlessMode;
+
+/**
+ * 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;
+
+/**
+ * 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);
+
+/* forward declarations: */
+struct VMMDevReqMousePointer;
+struct VMMDevMemory;
+
+/** @} */
+
+#endif
+
--- /dev/null
+/** @file
+ * VirtualBox - Common C and C++ definition.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___VBox_cdefs_h
+#define ___VBox_cdefs_h
+
+#include <iprt/cdefs.h>
+
+
+/** @defgroup 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
+
+
+/*
+ * Shut up DOXYGEN warnings and guide it properly thru the code.
+ */
+#ifdef DOXYGEN_RUNNING
+#define VBOX_WITH_STATISTICS
+#define VBOX_STRICT
+#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) DECLHIDDEN(type) VBOXCALL
+# else
+# define DISDECL(type) DECLEXPORT(type) VBOXCALL
+# endif
+#else
+# define DISDECL(type) DECLIMPORT(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) DECLEXPORT(type) VBOXCALL
+#else
+# define DBGDECL(type) DECLIMPORT(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) DECLEXPORT(type) VBOXCALL
+#else
+# define INTNETR3DECL(type) DECLIMPORT(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) DECLEXPORT(type) VBOXCALL
+#else
+# define INTNETR0DECL(type) DECLIMPORT(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) DECLEXPORT(type) VBOXCALL
+#else
+# define PCIRAWR3DECL(type) DECLIMPORT(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) DECLEXPORT(type) VBOXCALL
+#else
+# define PCIRAWR0DECL(type) DECLIMPORT(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) DECLEXPORT(type) VBOXCALL
+#else
+# define REMR3DECL(type) DECLIMPORT(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) DECLHIDDEN(type) VBOXCALL
+# else
+# define SUPR3DECL(type) DECLEXPORT(type) VBOXCALL
+# endif
+#else
+# ifdef IN_SUP_STATIC
+# define SUPR3DECL(type) DECLHIDDEN(type) VBOXCALL
+# else
+# define SUPR3DECL(type) DECLIMPORT(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) DECLHIDDEN(type) VBOXCALL
+# else
+# define SUPR0DECL(type) DECLEXPORT(type) VBOXCALL
+# endif
+#else
+# ifdef IN_SUP_STATIC
+# define SUPR0DECL(type) DECLHIDDEN(type) VBOXCALL
+# else
+# define SUPR0DECL(type) DECLIMPORT(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) DECLEXPORT(type) VBOXCALL
+#else
+# define SUPRCDECL(type) DECLIMPORT(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) DECLEXPORT(type) VBOXCALL
+#else
+# define SUPDECL(type) DECLIMPORT(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) DECLEXPORT(type) VBOXCALL
+#else
+# define USBLIB_DECL(type) DECLIMPORT(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) DECLHIDDEN(type) VBOXCALL
+# else
+# define VMMR3DECL(type) DECLEXPORT(type) VBOXCALL
+# endif
+#elif defined(IN_RING3)
+# ifdef IN_VMM_STATIC
+# define VMMR3DECL(type) DECLHIDDEN(type) VBOXCALL
+# else
+# define VMMR3DECL(type) DECLIMPORT(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) DECLEXPORT(type) VBOXCALL
+#elif defined(IN_RING0)
+# define VMMR0DECL(type) DECLIMPORT(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) DECLEXPORT(type) VBOXCALL
+#elif defined(IN_RC)
+# define VMMRCDECL(type) DECLIMPORT(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) DECLEXPORT(type) VBOXCALL
+#elif defined(IN_RING0) || defined(IN_RZ)
+# define VMMRZDECL(type) DECLIMPORT(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) DECLHIDDEN(type) VBOXCALL
+#elif defined(IN_VMM_R3) || defined(IN_VMM_R0) || defined(IN_VMM_RC)
+# define VMMDECL(type) DECLEXPORT(type) VBOXCALL
+#else
+# define VMMDECL(type) DECLIMPORT(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) DECLHIDDEN(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) DECLHIDDEN(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) DECLHIDDEN(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) DECLHIDDEN(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) DECLHIDDEN(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) DECLEXPORT(type) VBOXCALL
+# endif
+#else
+# define VBOXDDU_DECL(type) DECLIMPORT(type) VBOXCALL
+#endif
+
+/** @} */
+
+
+/** @defgroup grp_devdrv Device Emulations and Drivers
+ * @{ */
+/** @} */
+
+#endif
+
--- /dev/null
+/** @file
+ * VirtualBox Status Codes.
+ */
+
+/*
+ * Copyright (C) 2006-2017 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___VBox_err_h
+#define ___VBox_err_h
+
+#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)
+/** @} */
+
+
+/** @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.
+ * 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
+/** Reason for leaving RC: Emulate (MM)IO intensive code in the recompiler. */
+#define VINF_EM_RAW_EMULATE_IO_BLOCK 1140
+/** 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)
+/** @} */
+
+
+/** @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 debugger which was already halted.
+ * (This is a warning and not an error.) */
+#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)
+/** @} */
+
+
+/** @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 shadow page pool was flushed.
+ * This means that a global CR3 sync was flagged. Anyone receiving this kind of status
+ * will have to get down to a SyncCR3 ASAP. See also VINF_PGM_SYNC_CR3. */
+#define VERR_PGM_POOL_FLUSHED (-1620)
+/** The shadow page pool was cleared.
+ * This is a error code internal to the shadow page pool, it will be
+ * converted to a VERR_PGM_POOL_FLUSHED before leaving the pool code. */
+#define VERR_PGM_POOL_CLEARED (-1621)
+/** 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
+/** Reason for leaving RC: Paging mode changed.
+ * PGMChangeMode() uses this to force a switch to R3 so it can safely deal with
+ * a mode switch. */
+#define VINF_PGM_CHANGE_MODE 1624
+/** 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)
+/** @} */
+
+
+/** @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)
+/** @} */
+
+
+/** @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 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)
+/** @} */
+
+
+/** @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)
+/** The exception was dispatched for raw-mode execution. */
+#define VINF_TRPM_XCPT_DISPATCHED 2405
+/** Bad TRPM_TRAP_IN_OP. */
+#define VERR_TRPM_BAD_TRAP_IN_OP (-2406)
+/** Internal processing error \#1 in TRPM. */
+#define VERR_TRPM_IPE_1 (-2407)
+/** Internal processing error \#2 in TRPM. */
+#define VERR_TRPM_IPE_2 (-2408)
+/** Internal processing error \#3 in TRPM. */
+#define VERR_TRPM_IPE_3 (-2409)
+/** Got into a part of TRPM that is not used when HM (VT-x/AMD-V) is enabled. */
+#define VERR_TRPM_HM_IPE (-2410)
+/** @} */
+
+
+/** @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)
+/** @} */
+
+
+/** @name Virtual Machine Monitor (VMM) Status Codes
+ * @{
+ */
+/** Reason for leaving RZ: Calling host function. */
+#define VINF_VMM_CALL_HOST 2700
+/** 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 set jump error. */
+#define VERR_VMM_SET_JMP_ERROR (-2706)
+/** VMM set jump stack overflow error. */
+#define VERR_VMM_SET_JMP_STACK_OVERFLOW (-2707)
+/** VMM set jump resume error. */
+#define VERR_VMM_SET_JMP_ABORTED_RESUME (-2708)
+/** VMM long jump error. */
+#define VERR_VMM_LONG_JMP_ERROR (-2709)
+/** Unknown ring-3 call attempted. */
+#define VERR_VMM_UNKNOWN_RING3_CALL (-2710)
+/** The ring-3 call didn't set an RC. */
+#define VERR_VMM_RING3_CALL_NO_RC (-2711)
+/** 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)
+/** @} */
+
+
+/** @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_DEVHLPR3_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)
+/** @} */
+
+
+/** @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)
+
+/** @} */
+
+
+/** @name Network Address Translation Driver (DrvNAT) Status Codes
+ * @{
+ */
+/** Failed to find the DNS configured for this machine. */
+#define VINF_NAT_DNS 3000
+/** 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)
+
+/** @} */
+
+
+/** @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)
+/** @} */
+
+
+/** @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)
+/** @} */
+
+
+/** @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
+ * @{
+ */
+/** The GMM is out of pages and needs to be give another chunk of user memory that
+ * it can lock down and borrow pages from. */
+#define VERR_GMM_SEED_ME (-3800)
+/** 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)
+/** IA32_FEATURE_CONTROL MSR not setup correcty (turn on VMX in the host system BIOS) */
+#define VERR_VMX_ILLEGAL_FEATURE_CONTROL_MSR (-4007)
+/** Invalid CPU mode for VMX execution. */
+#define VERR_VMX_UNSUPPORTED_MODE (-4008)
+/** VMX CPU extension not available */
+#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)
+/** VM-Entry Controls internal cache invalid. */
+#define VERR_VMX_ENTRY_CTLS_CACHE_INVALID (-4030)
+/** VM-Exit Controls internal cache invalid. */
+#define VERR_VMX_EXIT_CTLS_CACHE_INVALID (-4031)
+/** VM-Execution Pin-based Controls internal cache invalid. */
+#define VERR_VMX_PIN_EXEC_CTLS_CACHE_INVALID (-4032)
+/** VM-Execution Primary Processor-based Controls internal cache
+ * invalid. */
+#define VERR_VMX_PROC_EXEC_CTLS_CACHE_INVALID (-4033)
+/** VM-Execution Secondary Processor-based Controls internal
+ * cache invalid. */
+#define VERR_VMX_PROC_EXEC2_CTLS_CACHE_INVALID (-4034)
+/** Failed to set VMXON enable bit while enabling VT-x through the MSR. */
+#define VERR_VMX_MSR_VMX_ENABLE_FAILED (-4035)
+/** Failed to enable VMXON-in-SMX bit while enabling VT-x through the MSR. */
+#define VERR_VMX_MSR_SMX_VMX_ENABLE_FAILED (-4036)
+/** @} */
+
+
+/** @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
+/** @} */
+
+
+/** @name VBox HM Status Codes
+ * @{
+ */
+/** Unable to start VM execution. */
+#define VERR_HM_UNKNOWN_CPU (-4100)
+/** No CPUID support. */
+#define VERR_HM_NO_CPUID (-4101)
+/** Host is about to go into suspend mode. */
+#define VERR_HM_SUSPEND_PENDING (-4102)
+/** 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
+/** The requested nested-guest VM-exit intercept is not active or not in
+ * nested-guest execution mode. */
+#define VINF_HM_INTERCEPT_NOT_ACTIVE 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 Passtrhough 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)
+/** @} */
+
+
+/** @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)
+/** @} */
+
+
+/** @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)
+
+/** @} */
+
+/** @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)
+/** Started guest process terminated with an exit code <> 0. */
+#define VWRN_GSTCTL_PROCESS_EXIT_CODE 6221
+/** @} */
+
+
+/** @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_GSTDND_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 free input streams. */
+#define VERR_AUDIO_NO_FREE_INPUT_STREAMS (-6601)
+/** No free output streams. */
+#define VERR_AUDIO_NO_FREE_OUTPUT_STREAMS (-6602)
+/** Pending stream disable operation in progress. */
+#define VERR_AUDIO_STREAM_PENDING_DISABLE (-6603)
+/** 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 (6604)
+/** @} */
+
+
+/** @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)
+/** @} */
+
+/* SED-END */
+
+/** @} */
+
+
+#endif
+
--- /dev/null
+/** @file
+ * Host-Guest Communication Manager (HGCM) - Service library definitions.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___VBox_hgcm_h
+#define ___VBox_hgcm_h
+
+#include <iprt/assert.h>
+#include <iprt/string.h>
+#include <VBox/cdefs.h>
+#include <VBox/types.h>
+#include <VBox/err.h>
+#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
+ */
+#define VBOX_HGCM_SVC_VERSION_MAJOR (0x0005)
+#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(void, pfnCallComplete, (VBOXHGCMCALLHANDLE callHandle, int32_t rc));
+
+ void *pvInstance;
+
+ /** The service disconnects the client. */
+ DECLR3CALLBACKMEMBER(void, pfnDisconnectClient, (void *pvInstance, uint32_t u32ClientID));
+} VBOXHGCMSVCHELPERS;
+
+typedef VBOXHGCMSVCHELPERS *PVBOXHGCMSVCHELPERS;
+
+
+#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)
+
+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;
+ } u;
+#ifdef __cplusplus
+ /** Extract an uint32_t value from an HGCM parameter structure */
+ int getUInt32(uint32_t *u32)
+ {
+ AssertPtrReturn(u32, VERR_INVALID_POINTER);
+ int rc = VINF_SUCCESS;
+ if (type != VBOX_HGCM_SVC_PARM_32BIT)
+ rc = VERR_INVALID_PARAMETER;
+ if (RT_SUCCESS(rc))
+ *u32 = u.uint32;
+ return rc;
+ }
+
+ /** Extract a uint64_t value from an HGCM parameter structure */
+ int getUInt64(uint64_t *u64)
+ {
+ AssertPtrReturn(u64, VERR_INVALID_POINTER);
+ int rc = VINF_SUCCESS;
+ if (type != VBOX_HGCM_SVC_PARM_64BIT)
+ rc = VERR_INVALID_PARAMETER;
+ if (RT_SUCCESS(rc))
+ *u64 = u.uint64;
+ return rc;
+ }
+
+ /** Extract a pointer value from an HGCM parameter structure */
+ int getPointer(void **ppv, uint32_t *pcb)
+ {
+ AssertPtrReturn(ppv, VERR_INVALID_POINTER);
+ AssertPtrReturn(pcb, VERR_INVALID_POINTER);
+ if (type == VBOX_HGCM_SVC_PARM_PTR)
+ {
+ *ppv = u.pointer.addr;
+ *pcb = u.pointer.size;
+ return VINF_SUCCESS;
+ }
+
+ return VERR_INVALID_PARAMETER;
+ }
+
+ /** Extract a constant pointer value from an HGCM parameter structure */
+ int getPointer(const void **ppcv, uint32_t *pcb)
+ {
+ AssertPtrReturn(ppcv, VERR_INVALID_POINTER);
+ AssertPtrReturn(pcb, VERR_INVALID_POINTER);
+ void *pv;
+ int rc = getPointer(&pv, pcb);
+ *ppcv = pv;
+ return rc;
+ }
+
+ /** Extract a pointer value to a non-empty buffer from an HGCM parameter
+ * structure */
+ int getBuffer(void **ppv, uint32_t *pcb)
+ {
+ AssertPtrReturn(ppv, VERR_INVALID_POINTER);
+ AssertPtrReturn(pcb, VERR_INVALID_POINTER);
+ void *pv = NULL;
+ uint32_t cb = 0;
+ int rc = getPointer(&pv, &cb);
+ if ( RT_SUCCESS(rc)
+ && VALID_PTR(pv)
+ && cb > 0)
+ {
+ *ppv = pv;
+ *pcb = cb;
+ return VINF_SUCCESS;
+ }
+
+ return VERR_INVALID_PARAMETER;
+ }
+
+ /** Extract a pointer value to a non-empty constant buffer from an HGCM
+ * parameter structure */
+ int getBuffer(const void **ppcv, uint32_t *pcb)
+ {
+ AssertPtrReturn(ppcv, VERR_INVALID_POINTER);
+ AssertPtrReturn(pcb, VERR_INVALID_POINTER);
+ void *pcv = NULL;
+ int rc = getBuffer(&pcv, pcb);
+ *ppcv = pcv;
+ return rc;
+ }
+
+ /** Extract a string value from an HGCM parameter structure */
+ int getString(char **ppch, uint32_t *pcb)
+ {
+ uint32_t cb = 0;
+ char *pch = NULL;
+ int rc = getBuffer((void **)&pch, &cb);
+ if (RT_FAILURE(rc))
+ {
+ *ppch = NULL;
+ *pcb = 0;
+ return rc;
+ }
+ rc = RTStrValidateEncodingEx(pch, cb,
+ RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED);
+ *ppch = pch;
+ *pcb = cb;
+ return rc;
+ }
+
+ /** Extract a constant string value from an HGCM parameter structure */
+ int getString(const char **ppch, uint32_t *pcb)
+ {
+ char *pch = NULL;
+ int rc = getString(&pch, pcb);
+ *ppch = pch;
+ return rc;
+ }
+
+ /** Set a uint32_t value to an HGCM parameter structure */
+ void setUInt32(uint32_t u32)
+ {
+ type = VBOX_HGCM_SVC_PARM_32BIT;
+ u.uint32 = u32;
+ }
+
+ /** Set a uint64_t value to an HGCM parameter structure */
+ void setUInt64(uint64_t u64)
+ {
+ type = VBOX_HGCM_SVC_PARM_64BIT;
+ u.uint64 = u64;
+ }
+
+ /** Set a pointer value to an HGCM parameter structure */
+ void setPointer(void *pv, uint32_t cb)
+ {
+ type = VBOX_HGCM_SVC_PARM_PTR;
+ u.pointer.addr = pv;
+ u.pointer.size = cb;
+ }
+
+ /** Set a const string value to an HGCM parameter structure */
+ void setString(const char *psz)
+ {
+ type = VBOX_HGCM_SVC_PARM_PTR;
+ u.pointer.addr = (void *)psz;
+ u.pointer.size = (uint32_t)strlen(psz) + 1;
+ }
+
+#ifdef ___iprt_cpp_ministring_h
+ /** Set a const string value to an HGCM parameter structure */
+ void setCppString(const RTCString &rString)
+ {
+ type = VBOX_HGCM_SVC_PARM_PTR;
+ u.pointer.addr = (void *)rString.c_str();
+ u.pointer.size = (uint32_t)rString.length() + 1;
+ }
+#endif
+
+#ifdef VBOX_TEST_HGCM_PARMS
+ /** Test the getString member function. Indirectly tests the getPointer
+ * and getBuffer APIs.
+ * @param hTest an running IPRT test
+ * @param aType the type that the parameter should be set to before
+ * calling getString
+ * @param apcc the value that the parameter should be set to before
+ * calling getString, and also the address (!) which we
+ * expect getString to return. Stricter than needed of
+ * course, but I was feeling lazy.
+ * @param acb the size that the parameter should be set to before
+ * calling getString, and also the size which we expect
+ * getString to return.
+ * @param rcExp the expected return value of the call to getString.
+ */
+ void doTestGetString(RTTEST hTest, uint32_t aType, const char *apcc,
+ uint32_t acb, int rcExp)
+ {
+ /* An RTTest API like this, which would print out an additional line
+ * of context if a test failed, would be nice. This is because the
+ * line number alone doesn't help much here, given that this is a
+ * subroutine called many times. */
+ /*
+ RTTestContextF(hTest,
+ ("doTestGetString, aType=%u, apcc=%p, acp=%u, rcExp=%Rrc",
+ aType, apcc, acp, rcExp));
+ */
+ setPointer((void *)apcc, acb);
+ type = aType; /* in case we don't want VBOX_HGCM_SVC_PARM_PTR */
+ const char *pcc = NULL;
+ uint32_t cb = 0;
+ int rc = getString(&pcc, &cb);
+ RTTEST_CHECK_RC(hTest, rc, rcExp);
+ if (RT_SUCCESS(rcExp))
+ {
+ RTTEST_CHECK_MSG_RETV(hTest, (pcc == apcc),
+ (hTest, "expected %p, got %p", apcc, pcc));
+ RTTEST_CHECK_MSG_RETV(hTest, (cb == acb),
+ (hTest, "expected %u, got %u", acb, cb));
+ }
+ }
+
+ /** Run some unit tests on the getString method and indirectly test
+ * getPointer and getBuffer as well. */
+ void testGetString(RTTEST hTest)
+ {
+ RTTestSub(hTest, "HGCM string parameter handling");
+ doTestGetString(hTest, VBOX_HGCM_SVC_PARM_32BIT, "test", 3,
+ VERR_INVALID_PARAMETER);
+ doTestGetString(hTest, VBOX_HGCM_SVC_PARM_PTR, "test", 5,
+ VINF_SUCCESS);
+ doTestGetString(hTest, VBOX_HGCM_SVC_PARM_PTR, "test", 3,
+ VERR_BUFFER_OVERFLOW);
+ doTestGetString(hTest, VBOX_HGCM_SVC_PARM_PTR, "test\xf0", 6,
+ VERR_INVALID_UTF8_ENCODING);
+ doTestGetString(hTest, VBOX_HGCM_SVC_PARM_PTR, "test", 0,
+ VERR_INVALID_PARAMETER);
+ doTestGetString(hTest, VBOX_HGCM_SVC_PARM_PTR, (const char *)0x1, 5,
+ VERR_INVALID_PARAMETER);
+ RTTestSubDone(hTest);
+ }
+#endif
+
+ VBOXHGCMSVCPARM() : type(VBOX_HGCM_SVC_PARM_INVALID) {}
+#endif
+} VBOXHGCMSVCPARM;
+
+typedef VBOXHGCMSVCPARM *PVBOXHGCMSVCPARM;
+
+#ifdef VBOX_WITH_CRHGSMI
+typedef void * HGCMCVSHANDLE;
+
+typedef DECLCALLBACK(void) HGCMHOSTFASTCALLCB (int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext);
+typedef HGCMHOSTFASTCALLCB *PHGCMHOSTFASTCALLCB;
+#endif
+
+
+/** 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 cbParm The size of the function parameters.
+ */
+typedef DECLCALLBACK(int) FNHGCMSVCEXT(void *pvExtension, uint32_t u32Function, void *pvParm, uint32_t cbParms);
+typedef FNHGCMSVCEXT *PFNHGCMSVCEXT;
+
+/** The Service DLL entry points.
+ *
+ * HGCM will call the DLL "VBoxHGCMSvcLoad"
+ * function and the DLL must fill in the VBOXHGCMSVCFNTABLE
+ * with function pointers.
+ */
+
+/* The structure is used in separately compiled binaries so an explicit packing is required. */
+#pragma pack(1) /** @todo r=bird: The pragma pack(1) is not at all required!! */
+typedef struct VBOXHGCMSVCFNTABLE
+{
+ /** @name Filled by HGCM
+ * @{ */
+
+ /** Size of the structure. */
+ uint32_t cbSize;
+
+ /** Version of the structure, including the helpers. */
+ uint32_t u32Version;
+
+ PVBOXHGCMSVCHELPERS pHelpers;
+ /** @} */
+
+ /** @name Filled in by the service.
+ * @{ */
+
+ /** Size of client information the service want to have. */
+ uint32_t cbClient;
+#if ARCH_BITS == 64
+ /** Ensure that the following pointers are properly aligned on 64-bit system. */
+ uint32_t u32Alignment0;
+#endif
+
+ /** Uninitialize service */
+ DECLR3CALLBACKMEMBER(int, pfnUnload, (void *pvService));
+
+ /** Inform the service about a client connection. */
+ DECLR3CALLBACKMEMBER(int, pfnConnect, (void *pvService, uint32_t u32ClientID, void *pvClient));
+
+ /** 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[]));
+
+ /** 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));
+
+ /** Inform the service about a VM load operation. */
+ DECLR3CALLBACKMEMBER(int, pfnLoadState, (void *pvService, uint32_t u32ClientID, void *pvClient, PSSMHANDLE pSSM));
+
+ /** Register a service extension callback. */
+ DECLR3CALLBACKMEMBER(int, pfnRegisterExtension, (void *pvService, PFNHGCMSVCEXT pfnExtension, void *pvExtension));
+
+ /** User/instance data pointer for the service. */
+ void *pvService;
+
+ /** @} */
+} VBOXHGCMSVCFNTABLE;
+#pragma pack()
+
+
+/** Service initialization entry point. */
+typedef DECLCALLBACK(int) VBOXHGCMSVCLOAD(VBOXHGCMSVCFNTABLE *ptable);
+typedef VBOXHGCMSVCLOAD *PFNVBOXHGCMSVCLOAD;
+#define VBOX_HGCM_SVCLOAD_NAME "VBoxHGCMSvcLoad"
+
+#endif
--- /dev/null
+/** @file
+ * VirtualBox - Logging.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___VBox_log_h
+#define ___VBox_log_h
+
+/*
+ * 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 LOGGROUP
+{
+ /** 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,
+ /** 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,
+ /** 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,
+ /** Floppy Controller Device group. */
+ LOG_GROUP_DEV_FDC,
+ /** 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,
+ /** I/O APIC Device group. */
+ LOG_GROUP_DEV_IOAPIC,
+ /** The internal networking IP stack Device group. */
+ LOG_GROUP_DEV_INIP,
+ /** 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,
+ /** 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,
+ /** 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,
+ /** 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,
+ /** 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,
+ /** 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,
+ /** IOM group. */
+ LOG_GROUP_IOM,
+ /** 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, tcpip.c TCPIP_DEBUG */
+ LOG_GROUP_LWIP_TCPIP,
+ /** 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, 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, IAdditionsStateChangedEvent. */
+ LOG_GROUP_MAIN_ADDITIONSSTATECHANGEDEVENT,
+ /** Main group, IAppliance. */
+ LOG_GROUP_MAIN_APPLIANCE,
+ /** Main group, IAudioAdapter. */
+ LOG_GROUP_MAIN_AUDIOADAPTER,
+ /** Main group, IBandwidthControl. */
+ LOG_GROUP_MAIN_BANDWIDTHCONTROL,
+ /** Main group, IBandwidthGroup. */
+ LOG_GROUP_MAIN_BANDWIDTHGROUP,
+ /** Main group, IBandwidthGroupChangedEvent. */
+ LOG_GROUP_MAIN_BANDWIDTHGROUPCHANGEDEVENT,
+ /** Main group, IBIOSSettings. */
+ LOG_GROUP_MAIN_BIOSSETTINGS,
+ /** Main group, ICanShowWindowEvent. */
+ LOG_GROUP_MAIN_CANSHOWWINDOWEVENT,
+ /** Main group, ICertificate. */
+ LOG_GROUP_MAIN_CERTIFICATE,
+ /** Main group, IClipboardModeChangedEvent. */
+ LOG_GROUP_MAIN_CLIPBOARDMODECHANGEDEVENT,
+ /** Main group, IConsole. */
+ LOG_GROUP_MAIN_CONSOLE,
+ /** Main group, ICPUChangedEvent. */
+ LOG_GROUP_MAIN_CPUCHANGEDEVENT,
+ /** Main group, ICPUExecutionCapChangedEvent. */
+ LOG_GROUP_MAIN_CPUEXECUTIONCAPCHANGEDEVENT,
+ /** 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, IDnDModeChangedEvent. */
+ LOG_GROUP_MAIN_DNDMODECHANGEDEVENT,
+ /** 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, IEventSourceChangedEvent. */
+ LOG_GROUP_MAIN_EVENTSOURCECHANGEDEVENT,
+ /** 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, IExtraDataCanChangeEvent. */
+ LOG_GROUP_MAIN_EXTRADATACANCHANGEEVENT,
+ /** Main group, IExtraDataChangedEvent. */
+ LOG_GROUP_MAIN_EXTRADATACHANGEDEVENT,
+ /** Main group, IFile. */
+ LOG_GROUP_MAIN_FILE,
+ /** Main group, IFramebuffer. */
+ LOG_GROUP_MAIN_FRAMEBUFFER,
+ /** Main group, IFramebufferOverlay. */
+ LOG_GROUP_MAIN_FRAMEBUFFEROVERLAY,
+ /** Main group, IFsObjInfo. */
+ LOG_GROUP_MAIN_FSOBJINFO,
+ /** Main group, IGuest. */
+ LOG_GROUP_MAIN_GUEST,
+ /** 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, IGuestFileOffsetChangedEvent. */
+ LOG_GROUP_MAIN_GUESTFILEOFFSETCHANGEDEVENT,
+ /** Main group, IGuestFileReadEvent. */
+ LOG_GROUP_MAIN_GUESTFILEREADEVENT,
+ /** Main group, IGuestFileRegisteredEvent. */
+ LOG_GROUP_MAIN_GUESTFILEREGISTEREDEVENT,
+ /** Main group, IGuestFileStateChangedEvent. */
+ LOG_GROUP_MAIN_GUESTFILESTATECHANGEDEVENT,
+ /** Main group, IGuestFileWriteEvent. */
+ LOG_GROUP_MAIN_GUESTFILEWRITEEVENT,
+ /** Main group, IGuestFsObjInfo. */
+ LOG_GROUP_MAIN_GUESTFSOBJINFO,
+ /** Main group, IGuestKeyboardEvent. */
+ LOG_GROUP_MAIN_GUESTKEYBOARDEVENT,
+ /** Main group, IGuestMonitorChangedEvent. */
+ LOG_GROUP_MAIN_GUESTMONITORCHANGEDEVENT,
+ /** Main group, IGuestMouseEvent. */
+ LOG_GROUP_MAIN_GUESTMOUSEEVENT,
+ /** Main group, IGuestMultiTouchEvent. */
+ LOG_GROUP_MAIN_GUESTMULTITOUCHEVENT,
+ /** Main group, IGuestOSType. */
+ LOG_GROUP_MAIN_GUESTOSTYPE,
+ /** Main group, IGuestProcess. */
+ LOG_GROUP_MAIN_GUESTPROCESS,
+ /** Main group, IGuestProcessEvent. */
+ LOG_GROUP_MAIN_GUESTPROCESSEVENT,
+ /** Main group, IGuestProcessInputNotifyEvent. */
+ LOG_GROUP_MAIN_GUESTPROCESSINPUTNOTIFYEVENT,
+ /** Main group, IGuestProcessIOEvent. */
+ LOG_GROUP_MAIN_GUESTPROCESSIOEVENT,
+ /** Main group, IGuestProcessOutputEvent. */
+ LOG_GROUP_MAIN_GUESTPROCESSOUTPUTEVENT,
+ /** Main group, IGuestProcessRegisteredEvent. */
+ LOG_GROUP_MAIN_GUESTPROCESSREGISTEREDEVENT,
+ /** Main group, IGuestProcessStateChangedEvent. */
+ LOG_GROUP_MAIN_GUESTPROCESSSTATECHANGEDEVENT,
+ /** Main group, IGuestPropertyChangedEvent. */
+ LOG_GROUP_MAIN_GUESTPROPERTYCHANGEDEVENT,
+ /** Main group, IGuestScreenInfo. */
+ LOG_GROUP_MAIN_GUESTSCREENINFO,
+ /** Main group, IGuestSession. */
+ LOG_GROUP_MAIN_GUESTSESSION,
+ /** Main group, IGuestSessionEvent. */
+ LOG_GROUP_MAIN_GUESTSESSIONEVENT,
+ /** Main group, IGuestSessionRegisteredEvent. */
+ LOG_GROUP_MAIN_GUESTSESSIONREGISTEREDEVENT,
+ /** Main group, IGuestSessionStateChangedEvent. */
+ LOG_GROUP_MAIN_GUESTSESSIONSTATECHANGEDEVENT,
+ /** Main group, IGuestUserStateChangedEvent. */
+ LOG_GROUP_MAIN_GUESTUSERSTATECHANGEDEVENT,
+ /** Main group, IHost. */
+ LOG_GROUP_MAIN_HOST,
+ /** Main group, IHostNameResolutionConfigurationChangeEvent. */
+ LOG_GROUP_MAIN_HOSTNAMERESOLUTIONCONFIGURATIONCHANGEEVENT,
+ /** Main group, IHostNetworkInterface. */
+ LOG_GROUP_MAIN_HOSTNETWORKINTERFACE,
+ /** Main group, IHostPCIDevicePlugEvent. */
+ LOG_GROUP_MAIN_HOSTPCIDEVICEPLUGEVENT,
+ /** 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, IKeyboardLedsChangedEvent. */
+ LOG_GROUP_MAIN_KEYBOARDLEDSCHANGEDEVENT,
+ /** Main group, IMachine. */
+ LOG_GROUP_MAIN_MACHINE,
+ /** Main group, IMachineDataChangedEvent. */
+ LOG_GROUP_MAIN_MACHINEDATACHANGEDEVENT,
+ /** Main group, IMachineDebugger. */
+ LOG_GROUP_MAIN_MACHINEDEBUGGER,
+ /** Main group, IMachineEvent. */
+ LOG_GROUP_MAIN_MACHINEEVENT,
+ /** Main group, IMachineRegisteredEvent. */
+ LOG_GROUP_MAIN_MACHINEREGISTEREDEVENT,
+ /** Main group, IMachineStateChangedEvent. */
+ LOG_GROUP_MAIN_MACHINESTATECHANGEDEVENT,
+ /** Main group, IMedium. */
+ LOG_GROUP_MAIN_MEDIUM,
+ /** Main group, IMediumAttachment. */
+ LOG_GROUP_MAIN_MEDIUMATTACHMENT,
+ /** Main group, IMediumChangedEvent. */
+ LOG_GROUP_MAIN_MEDIUMCHANGEDEVENT,
+ /** Main group, IMediumConfigChangedEvent. */
+ LOG_GROUP_MAIN_MEDIUMCONFIGCHANGEDEVENT,
+ /** Main group, IMediumFormat. */
+ LOG_GROUP_MAIN_MEDIUMFORMAT,
+ /** Main group, IMediumRegisteredEvent. */
+ LOG_GROUP_MAIN_MEDIUMREGISTEREDEVENT,
+ /** Main group, IMouse. */
+ LOG_GROUP_MAIN_MOUSE,
+ /** Main group, IMouseCapabilityChangedEvent. */
+ LOG_GROUP_MAIN_MOUSECAPABILITYCHANGEDEVENT,
+ /** Main group, IMousePointerShape. */
+ LOG_GROUP_MAIN_MOUSEPOINTERSHAPE,
+ /** Main group, IMousePointerShapeChangedEvent. */
+ LOG_GROUP_MAIN_MOUSEPOINTERSHAPECHANGEDEVENT,
+ /** Main group, INATEngine. */
+ LOG_GROUP_MAIN_NATENGINE,
+ /** Main group, INATNetwork. */
+ LOG_GROUP_MAIN_NATNETWORK,
+ /** Main group, INATNetworkAlterEvent. */
+ LOG_GROUP_MAIN_NATNETWORKALTEREVENT,
+ /** Main group, INATNetworkChangedEvent. */
+ LOG_GROUP_MAIN_NATNETWORKCHANGEDEVENT,
+ /** Main group, INATNetworkCreationDeletionEvent. */
+ LOG_GROUP_MAIN_NATNETWORKCREATIONDELETIONEVENT,
+ /** Main group, INATNetworkPortForwardEvent. */
+ LOG_GROUP_MAIN_NATNETWORKPORTFORWARDEVENT,
+ /** Main group, INATNetworkSettingEvent. */
+ LOG_GROUP_MAIN_NATNETWORKSETTINGEVENT,
+ /** Main group, INATNetworkStartStopEvent. */
+ LOG_GROUP_MAIN_NATNETWORKSTARTSTOPEVENT,
+ /** Main group, INATRedirectEvent. */
+ LOG_GROUP_MAIN_NATREDIRECTEVENT,
+ /** Main group, INetworkAdapter. */
+ LOG_GROUP_MAIN_NETWORKADAPTER,
+ /** Main group, INetworkAdapterChangedEvent. */
+ LOG_GROUP_MAIN_NETWORKADAPTERCHANGEDEVENT,
+ /** Main group, IParallelPort. */
+ LOG_GROUP_MAIN_PARALLELPORT,
+ /** Main group, IParallelPortChangedEvent. */
+ LOG_GROUP_MAIN_PARALLELPORTCHANGEDEVENT,
+ /** 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, IReusableEvent. */
+ LOG_GROUP_MAIN_REUSABLEEVENT,
+ /** Main group, IRuntimeErrorEvent. */
+ LOG_GROUP_MAIN_RUNTIMEERROREVENT,
+ /** Main group, ISerialPort. */
+ LOG_GROUP_MAIN_SERIALPORT,
+ /** Main group, ISerialPortChangedEvent. */
+ LOG_GROUP_MAIN_SERIALPORTCHANGEDEVENT,
+ /** Main group, ISession. */
+ LOG_GROUP_MAIN_SESSION,
+ /** Main group, ISessionStateChangedEvent. */
+ LOG_GROUP_MAIN_SESSIONSTATECHANGEDEVENT,
+ /** Main group, ISharedFolder. */
+ LOG_GROUP_MAIN_SHAREDFOLDER,
+ /** Main group, ISharedFolderChangedEvent. */
+ LOG_GROUP_MAIN_SHAREDFOLDERCHANGEDEVENT,
+ /** Main group, IShowWindowEvent. */
+ LOG_GROUP_MAIN_SHOWWINDOWEVENT,
+ /** Main group, ISnapshot. */
+ LOG_GROUP_MAIN_SNAPSHOT,
+ /** Main group, ISnapshotChangedEvent. */
+ LOG_GROUP_MAIN_SNAPSHOTCHANGEDEVENT,
+ /** Main group, ISnapshotDeletedEvent. */
+ LOG_GROUP_MAIN_SNAPSHOTDELETEDEVENT,
+ /** Main group, ISnapshotEvent. */
+ LOG_GROUP_MAIN_SNAPSHOTEVENT,
+ /** Main group, ISnapshotTakenEvent. */
+ LOG_GROUP_MAIN_SNAPSHOTRESTOREDEVENT,
+ /** Main group, ISnapshotRestoredEvent. */
+ LOG_GROUP_MAIN_SNAPSHOTTAKENEVENT,
+ /** Main group, IStateChangedEvent. */
+ LOG_GROUP_MAIN_STATECHANGEDEVENT,
+ /** Main group, IStorageController. */
+ LOG_GROUP_MAIN_STORAGECONTROLLER,
+ /** Main group, IStorageControllerChangedEvent. */
+ LOG_GROUP_MAIN_STORAGECONTROLLERCHANGEDEVENT,
+ /** Main group, IStorageDeviceChangedEvent. */
+ LOG_GROUP_MAIN_STORAGEDEVICECHANGEDEVENT,
+ /** Main group, ISystemProperties. */
+ LOG_GROUP_MAIN_SYSTEMPROPERTIES,
+ /** Main group, IToken. */
+ LOG_GROUP_MAIN_TOKEN,
+ /** Main group, IUSBController. */
+ LOG_GROUP_MAIN_USBCONTROLLER,
+ /** Main group, IUSBControllerChangedEvent. */
+ LOG_GROUP_MAIN_USBCONTROLLERCHANGEDEVENT,
+ /** Main group, IUSBDevice. */
+ LOG_GROUP_MAIN_USBDEVICE,
+ /** Main group, IUSBDeviceFilter. */
+ LOG_GROUP_MAIN_USBDEVICEFILTER,
+ /** Main group, IUSBDeviceFilters. */
+ LOG_GROUP_MAIN_USBDEVICEFILTERS,
+ /** Main group, IUSBDeviceStateChangedEvent. */
+ LOG_GROUP_MAIN_USBDEVICESTATECHANGEDEVENT,
+ /** Main group, IUSBProxyBackend. */
+ LOG_GROUP_MAIN_USBPROXYBACKEND,
+ /** Main group, IVBoxSVCAvailabilityChangedEvent. */
+ LOG_GROUP_MAIN_VBOXSVCAVAILABILITYCHANGEDEVENT,
+ /** Main group, IVetoEvent. */
+ LOG_GROUP_MAIN_VETOEVENT,
+ /** Main group, IVFSExplorer. */
+ LOG_GROUP_MAIN_VFSEXPLORER,
+ /** Main group, IVideoCaptureChangedEvent. */
+ LOG_GROUP_MAIN_VIDEOCAPTURECHANGEDEVENT,
+ /** Main group, IVirtualBox. */
+ LOG_GROUP_MAIN_VIRTUALBOX,
+ /** Main group, IVirtualBoxClient. */
+ LOG_GROUP_MAIN_VIRTUALBOXCLIENT,
+ /** Main group, IVirtualSystemDescription. */
+ LOG_GROUP_MAIN_VIRTUALSYSTEMDESCRIPTION,
+ /** Main group, IVRDEServer. */
+ LOG_GROUP_MAIN_VRDESERVER,
+ /** Main group, IVRDEServerChangedEvent. */
+ LOG_GROUP_MAIN_VRDESERVERCHANGEDEVENT,
+ /** Main group, IVRDEServerInfo. */
+ LOG_GROUP_MAIN_VRDESERVERINFO,
+ /** Main group, IVRDEServerInfoChangedEvent. */
+ LOG_GROUP_MAIN_VRDESERVERINFOCHANGEDEVENT,
+ /** 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,
+ /** The network adaptor driver group. */
+ LOG_GROUP_NET_ADP_DRV,
+ /** 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 Device group. */
+ LOG_GROUP_PDM_DEVICE,
+ /** PDM Driver group. */
+ LOG_GROUP_PDM_DRIVER,
+ /** PDM Loader group. */
+ LOG_GROUP_PDM_LDR,
+ /** PDM Loader group. */
+ LOG_GROUP_PDM_QUEUE,
+ /** 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,
+ /** 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 Driver (VBoxGuest). */
+ LOG_GROUP_VGDRV,
+ /** VBox Guest Additions Library. */
+ LOG_GROUP_VBGL,
+ /** Generic virtual disk layer. */
+ LOG_GROUP_VD,
+ /** 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,
+ /** 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!!! */
+} VBOX_LOGGROUP;
+
+
+/** @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", \
+ "AUTOLOGON", \
+ "CFGM", \
+ "CPUM", \
+ "CSAM", \
+ "DBGC", \
+ "DBGF", \
+ "DBGF_INFO", \
+ "DBGG", \
+ "DEV", \
+ "DEV_AC97", \
+ "DEV_ACPI", \
+ "DEV_AHCI", \
+ "DEV_APIC", \
+ "DEV_BUSLOGIC", \
+ "DEV_DMA", \
+ "DEV_E1000", \
+ "DEV_EFI", \
+ "DEV_EHCI", \
+ "DEV_FDC", \
+ "DEV_GIM", \
+ "DEV_HDA", \
+ "DEV_HDA_CODEC", \
+ "DEV_HPET", \
+ "DEV_IDE", \
+ "DEV_IOAPIC", \
+ "DEV_INIP", \
+ "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_RTC", \
+ "DEV_SB16", \
+ "DEV_SERIAL", \
+ "DEV_SMC", \
+ "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_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_TRANSPORT_ASYNC", \
+ "DRV_TUN", \
+ "DRV_UDP", \
+ "DRV_UDPTUNNEL", \
+ "DRV_USBPROXY", \
+ "DRV_VBOXHDD", \
+ "DRV_VD", \
+ "DRV_VRDE_AUDIO", \
+ "DRV_VSWITCH", \
+ "DRV_VUSB", \
+ "EM", \
+ "FTM", \
+ "GIM", \
+ "GMM", \
+ "GUEST_CONTROL", \
+ "GUEST_DND", \
+ "GUI", \
+ "GVMM", \
+ "HGCM", \
+ "HGSMI", \
+ "HM", \
+ "IEM", \
+ "IOM", \
+ "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_TCPIP", \
+ "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_TIMERS", \
+ "LWIP_UDP", \
+ "MAIN", \
+ "MAIN_ADDITIONSFACILITY", \
+ "MAIN_ADDITIONSSTATECHANGEDEVENT", \
+ "MAIN_APPLIANCE", \
+ "MAIN_AUDIOADAPTER", \
+ "MAIN_BANDWIDTHCONTROL", \
+ "MAIN_BANDWIDTHGROUP", \
+ "MAIN_BANDWIDTHGROUPCHANGEDEVENT", \
+ "MAIN_BIOSSETTINGS", \
+ "MAIN_CANSHOWWINDOWEVENT", \
+ "MAIN_CERTIFICATE", \
+ "MAIN_CLIPBOARDMODECHANGEDEVENT", \
+ "MAIN_CONSOLE", \
+ "MAIN_CPUCHANGEDEVENT", \
+ "MAIN_CPUEXECUTIONCAPCHANGEDEVENT", \
+ "MAIN_DHCPSERVER", \
+ "MAIN_DIRECTORY", \
+ "MAIN_DISPLAY", \
+ "MAIN_DISPLAYSOURCEBITMAP", \
+ "MAIN_DNDBASE", \
+ "MAIN_DNDMODECHANGEDEVENT", \
+ "MAIN_DNDSOURCE", \
+ "MAIN_DNDTARGET", \
+ "MAIN_EMULATEDUSB", \
+ "MAIN_EVENT", \
+ "MAIN_EVENTLISTENER", \
+ "MAIN_EVENTSOURCE", \
+ "MAIN_EVENTSOURCECHANGEDEVENT", \
+ "MAIN_EXTPACK", \
+ "MAIN_EXTPACKBASE", \
+ "MAIN_EXTPACKFILE", \
+ "MAIN_EXTPACKMANAGER", \
+ "MAIN_EXTPACKPLUGIN", \
+ "MAIN_EXTRADATACANCHANGEEVENT", \
+ "MAIN_EXTRADATACHANGEDEVENT", \
+ "MAIN_FILE", \
+ "MAIN_FRAMEBUFFER", \
+ "MAIN_FRAMEBUFFEROVERLAY", \
+ "MAIN_FSOBJINFO", \
+ "MAIN_GUEST", \
+ "MAIN_GUESTDIRECTORY", \
+ "MAIN_GUESTDNDSOURCE", \
+ "MAIN_GUESTDNDTARGET", \
+ "MAIN_GUESTERRORINFO", \
+ "MAIN_GUESTFILE", \
+ "MAIN_GUESTFILEEVENT", \
+ "MAIN_GUESTFILEIOEVENT", \
+ "MAIN_GUESTFILEOFFSETCHANGEDEVENT", \
+ "MAIN_GUESTFILEREADEVENT", \
+ "MAIN_GUESTFILEREGISTEREDEVENT", \
+ "MAIN_GUESTFILESTATECHANGEDEVENT", \
+ "MAIN_GUESTFILEWRITEEVENT", \
+ "MAIN_GUESTFSOBJINFO", \
+ "MAIN_GUESTKEYBOARDEVENT", \
+ "MAIN_GUESTMONITORCHANGEDEVENT", \
+ "MAIN_GUESTMOUSEEVENT", \
+ "MAIN_GUESTMULTITOUCHEVENT", \
+ "MAIN_GUESTOSTYPE", \
+ "MAIN_GUESTPROCESS", \
+ "MAIN_GUESTPROCESSEVENT", \
+ "MAIN_GUESTPROCESSINPUTNOTIFYEVENT", \
+ "MAIN_GUESTPROCESSIOEVENT", \
+ "MAIN_GUESTPROCESSOUTPUTEVENT", \
+ "MAIN_GUESTPROCESSREGISTEREDEVENT", \
+ "MAIN_GUESTPROCESSSTATECHANGEDEVENT", \
+ "MAIN_GUESTPROPERTYCHANGEDEVENT", \
+ "MAIN_GUESTSCREENINFO", \
+ "MAIN_GUESTSESSION", \
+ "MAIN_GUESTSESSIONEVENT", \
+ "MAIN_GUESTSESSIONREGISTEREDEVENT", \
+ "MAIN_GUESTSESSIONSTATECHANGEDEVENT", \
+ "MAIN_GUESTUSERSTATECHANGEDEVENT", \
+ "MAIN_HOST", \
+ "MAIN_HOSTNAMERESOLUTIONCONFIGURATIONCHANGEEVENT", \
+ "MAIN_HOSTNETWORKINTERFACE", \
+ "MAIN_HOSTPCIDEVICEPLUGEVENT", \
+ "MAIN_HOSTUSBDEVICE", \
+ "MAIN_HOSTUSBDEVICEFILTER", \
+ "MAIN_HOSTVIDEOINPUTDEVICE", \
+ "MAIN_INTERNALMACHINECONTROL", \
+ "MAIN_INTERNALSESSIONCONTROL", \
+ "MAIN_KEYBOARD", \
+ "MAIN_KEYBOARDLEDSCHANGEDEVENT", \
+ "MAIN_MACHINE", \
+ "MAIN_MACHINEDATACHANGEDEVENT", \
+ "MAIN_MACHINEDEBUGGER", \
+ "MAIN_MACHINEEVENT", \
+ "MAIN_MACHINEREGISTEREDEVENT", \
+ "MAIN_MACHINESTATECHANGEDEVENT", \
+ "MAIN_MEDIUM", \
+ "MAIN_MEDIUMATTACHMENT", \
+ "MAIN_MEDIUMCHANGEDEVENT", \
+ "MAIN_MEDIUMCONFIGCHANGEDEVENT", \
+ "MAIN_MEDIUMFORMAT", \
+ "MAIN_MEDIUMREGISTEREDEVENT", \
+ "MAIN_MOUSE", \
+ "MAIN_MOUSECAPABILITYCHANGEDEVENT", \
+ "MAIN_MOUSEPOINTERSHAPE", \
+ "MAIN_MOUSEPOINTERSHAPECHANGEDEVENT", \
+ "MAIN_NATENGINE", \
+ "MAIN_NATNETWORK", \
+ "MAIN_NATNETWORKALTEREVENT", \
+ "MAIN_NATNETWORKCHANGEDEVENT", \
+ "MAIN_NATNETWORKCREATIONDELETIONEVENT", \
+ "MAIN_NATNETWORKPORTFORWARDEVENT", \
+ "MAIN_NATNETWORKSETTINGEVENT", \
+ "MAIN_NATNETWORKSTARTSTOPEVENT", \
+ "MAIN_NATREDIRECTEVENT", \
+ "MAIN_NETWORKADAPTER", \
+ "MAIN_NETWORKADAPTERCHANGEDEVENT", \
+ "MAIN_PARALLELPORT", \
+ "MAIN_PARALLELPORTCHANGEDEVENT", \
+ "MAIN_PCIADDRESS", \
+ "MAIN_PCIDEVICEATTACHMENT", \
+ "MAIN_PERFORMANCECOLLECTOR", \
+ "MAIN_PERFORMANCEMETRIC", \
+ "MAIN_PROCESS", \
+ "MAIN_PROGRESS", \
+ "MAIN_REUSABLEEVENT", \
+ "MAIN_RUNTIMEERROREVENT", \
+ "MAIN_SERIALPORT", \
+ "MAIN_SERIALPORTCHANGEDEVENT", \
+ "MAIN_SESSION", \
+ "MAIN_SESSIONSTATECHANGEDEVENT", \
+ "MAIN_SHAREDFOLDER", \
+ "MAIN_SHAREDFOLDERCHANGEDEVENT", \
+ "MAIN_SHOWWINDOWEVENT", \
+ "MAIN_SNAPSHOT", \
+ "MAIN_SNAPSHOTCHANGEDEVENT", \
+ "MAIN_SNAPSHOTDELETEDEVENT", \
+ "MAIN_SNAPSHOTEVENT", \
+ "MAIN_SNAPSHOTRESTOREDEVENT", \
+ "MAIN_SNAPSHOTTAKENEVENT", \
+ "MAIN_STATECHANGEDEVENT", \
+ "MAIN_STORAGECONTROLLER", \
+ "MAIN_STORAGECONTROLLERCHANGEDEVENT", \
+ "MAIN_STORAGEDEVICECHANGEDEVENT", \
+ "MAIN_SYSTEMPROPERTIES", \
+ "MAIN_TOKEN", \
+ "MAIN_USBCONTROLLER", \
+ "MAIN_USBCONTROLLERCHANGEDEVENT", \
+ "MAIN_USBDEVICE", \
+ "MAIN_USBDEVICEFILTER", \
+ "MAIN_USBDEVICEFILTERS", \
+ "MAIN_USBDEVICESTATECHANGEDEVENT", \
+ "MAIN_USBPROXYBACKEND", \
+ "MAIN_VBOXSVCAVAILABILITYCHANGEDEVENT", \
+ "MAIN_VETOEVENT", \
+ "MAIN_VFSEXPLORER", \
+ "MAIN_VIDEOCAPTURECHANGEDEVENT", \
+ "MAIN_VIRTUALBOX", \
+ "MAIN_VIRTUALBOXCLIENT", \
+ "MAIN_VIRTUALSYSTEMDESCRIPTION", \
+ "MAIN_VRDESERVER", \
+ "MAIN_VRDESERVERCHANGEDEVENT", \
+ "MAIN_VRDESERVERINFO", \
+ "MAIN_VRDESERVERINFOCHANGEDEVENT", \
+ "MISC", \
+ "MM", \
+ "MM_HEAP", \
+ "MM_HYPER", \
+ "MM_HYPER_HEAP",\
+ "MM_PHYS", \
+ "MM_POOL", \
+ "NAT_SERVICE", \
+ "NET_ADP_DRV", \
+ "NET_FLT_DRV", \
+ "NET_SERVICE", \
+ "NET_SHAPER", \
+ "PATM", \
+ "PDM", \
+ "PDM_ASYNC_COMPLETION", \
+ "PDM_BLK_CACHE", \
+ "PDM_DEVICE", \
+ "PDM_DRIVER", \
+ "PDM_LDR", \
+ "PDM_QUEUE", \
+ "PGM", \
+ "PGM_DYNMAP", \
+ "PGM_PHYS", \
+ "PGM_PHYS_ACCESS",\
+ "PGM_POOL", \
+ "PGM_SHARED", \
+ "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", \
+ "VGDRV", \
+ "VBGL", \
+ "VD", \
+ "VD_DMG", \
+ "VD_ISCSI", \
+ "VD_PARALLELS", \
+ "VD_QCOW", \
+ "VD_QED", \
+ "VD_RAW", \
+ "VD_VDI", \
+ "VD_VHD", \
+ "VD_VHDX", \
+ "VD_VMDK", \
+ "VM", \
+ "VMM", \
+ "VRDE", \
+ "VRDP", \
+ "VSCSI", \
+ "WEBSERVICE", \
+}
+
+/** @} */
+#endif
--- /dev/null
+/** @file
+ * VirtualBox - Global Guest Operating System definition.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___VBox_ostypes_h
+#define ___VBox_ostypes_h
+
+#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.
+ *
+ * Note: distinguish between 32 & 64 bits guest OSes by checking bit 8 (mod 0x100)
+ */
+typedef enum VBOXOSTYPE
+{
+ VBOXOSTYPE_Unknown = 0,
+ VBOXOSTYPE_Unknown_x64 = 0x00100,
+ 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_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_OS2 = 0x40000,
+ VBOXOSTYPE_OS2Warp3 = 0x41000,
+ VBOXOSTYPE_OS2Warp4 = 0x42000,
+ VBOXOSTYPE_OS2Warp45 = 0x43000,
+ VBOXOSTYPE_ECS = 0x44000,
+ VBOXOSTYPE_OS21x = 0x48000,
+ 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_OpenSUSE = 0x56000,
+ VBOXOSTYPE_OpenSUSE_x64 = 0x56100,
+ VBOXOSTYPE_FedoraCore = 0x57000,
+ VBOXOSTYPE_FedoraCore_x64 = 0x57100,
+ VBOXOSTYPE_Gentoo = 0x58000,
+ VBOXOSTYPE_Gentoo_x64 = 0x58100,
+ VBOXOSTYPE_Mandriva = 0x59000,
+ VBOXOSTYPE_Mandriva_x64 = 0x59100,
+ VBOXOSTYPE_RedHat = 0x5A000,
+ VBOXOSTYPE_RedHat_x64 = 0x5A100,
+ VBOXOSTYPE_Turbolinux = 0x5B000,
+ VBOXOSTYPE_Turbolinux_x64 = 0x5B100,
+ VBOXOSTYPE_Ubuntu = 0x5C000,
+ VBOXOSTYPE_Ubuntu_x64 = 0x5C100,
+ VBOXOSTYPE_Xandros = 0x5D000,
+ VBOXOSTYPE_Xandros_x64 = 0x5D100,
+ VBOXOSTYPE_Oracle = 0x5E000,
+ VBOXOSTYPE_Oracle_x64 = 0x5E100,
+ 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,
+ VBOXOSTYPE_Solaris_x64 = 0x80100,
+ 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,
+ VBOXOSTYPE_JRockitVE = 0xC0000,
+ VBOXOSTYPE_Haiku = 0xD0000,
+ VBOXOSTYPE_Haiku_x64 = 0xD0100,
+ VBOXOSTYPE_VBoxBS_x64 = 0xE0100,
+/** The bit number which indicates 64-bit or 32-bit. */
+#define VBOXOSTYPE_x64_BIT 8
+ /** The mask which indicates 64-bit. */
+ VBOXOSTYPE_x64 = 1 << VBOXOSTYPE_x64_BIT,
+ /** 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
--- /dev/null
+/** @file
+ * VirtualBox Parameter Definitions. (VMM,+)
+ *
+ * param.mac is generated from this file by running 'kmk incs' in the root.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___VBox_param_h
+#define ___VBox_param_h
+
+#include <iprt/param.h>
+#include <iprt/cdefs.h>
+
+
+/** @defgroup grp_vbox_param VBox Parameter Definition
+ * @{
+ */
+
+/** 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_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
+
--- /dev/null
+/** @file
+ * Shared Folders: Common header for host service and guest clients.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___VBox_shflsvc_h
+#define ___VBox_shflsvc_h
+
+#include <VBox/types.h>
+#include <VBox/VBoxGuest2.h>
+#include <VBox/VMMDev.h>
+#include <VBox/hgcmsvc.h>
+#include <iprt/fs.h>
+
+
+/** @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
+/** @} */
+
+
+/**
+ * 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.
+ */
+
+/** Shared Folders service functions. (guest)
+ * @{
+ */
+
+/** Query mappings changes. */
+#define SHFL_FN_QUERY_MAPPINGS (1)
+/** Query mappings changes. */
+#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 (as of VBox 4.0) */
+#define SHFL_FN_READLINK (18)
+/** Create symlink (as of VBox 4.0) */
+#define SHFL_FN_SYMLINK (19)
+/** Ask host to show symlinks (as of VBox 4.0) */
+#define SHFL_FN_SET_SYMLINKS (20)
+
+/** @} */
+
+/** 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 (as of 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;
+
+#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.
+ */
+#pragma pack(1)
+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
+ {
+ uint8_t utf8[1];
+ uint16_t ucs2[1];
+ } String;
+} SHFLSTRING;
+#pragma pack()
+
+#define SHFLSTRING_HEADER_SIZE RT_UOFFSETOF(SHFLSTRING, String)
+
+/** 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)(sizeof(SHFLSTRING) - sizeof(pString->String) + 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;
+}
+
+/**
+ * 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;
+}
+
+/** @} */
+
+
+/**
+ * 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;
+ 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
+} SHFLCREATERESULT;
+
+
+/** 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;
+
+
+/** 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. */
+ uint32_t u32Status;
+ /** Root handle. */
+ SHFLROOT root;
+} SHFLMAPPING;
+/** Pointer to a SHFLMAPPING structure. */
+typedef SHFLMAPPING *PSHFLMAPPING;
+
+/** @} */
+
+/** 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;
+
+/** @} */
+
+/** Function parameter structures.
+ * @{
+ */
+
+/**
+ * SHFL_FN_QUERY_MAPPINGS
+ */
+/** Validation mask. Needs to be adjusted
+ * whenever a new SHFL_MF_ flag is added. */
+#define SHFL_MF_MASK (0x00000011)
+/** UC2 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)
+
+/** Type of guest system. For future system dependent features. */
+#define SHFL_MF_SYSTEM_MASK (0x0000FF00)
+#define SHFL_MF_SYSTEM_NONE (0x00000000)
+#define SHFL_MF_SYSTEM_WINDOWS (0x00000100)
+#define SHFL_MF_SYSTEM_LINUX (0x00000200)
+
+/** Parameters structure. */
+typedef struct _VBoxSFQueryMappings
+{
+ VBoxGuestHGCMCallInfo 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)
+
+
+
+/**
+ * SHFL_FN_QUERY_MAP_NAME
+ */
+
+/** Parameters structure. */
+typedef struct _VBoxSFQueryMapName
+{
+ VBoxGuestHGCMCallInfo 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)
+
+/**
+ * SHFL_FN_MAP_FOLDER_OLD
+ */
+
+/** Parameters structure. */
+typedef struct _VBoxSFMapFolder_Old
+{
+ VBoxGuestHGCMCallInfo 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)
+
+/**
+ * SHFL_FN_MAP_FOLDER
+ */
+
+/** Parameters structure. */
+typedef struct _VBoxSFMapFolder
+{
+ VBoxGuestHGCMCallInfo 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)
+
+/**
+ * SHFL_FN_UNMAP_FOLDER
+ */
+
+/** Parameters structure. */
+typedef struct _VBoxSFUnmapFolder
+{
+ VBoxGuestHGCMCallInfo 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)
+
+
+/**
+ * SHFL_FN_CREATE
+ */
+
+/** Parameters structure. */
+typedef struct _VBoxSFCreate
+{
+ VBoxGuestHGCMCallInfo 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)
+
+
+/**
+ * SHFL_FN_CLOSE
+ */
+
+/** Parameters structure. */
+typedef struct _VBoxSFClose
+{
+ VBoxGuestHGCMCallInfo 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)
+
+
+/**
+ * SHFL_FN_READ
+ */
+
+/** Parameters structure. */
+typedef struct _VBoxSFRead
+{
+ VBoxGuestHGCMCallInfo 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)
+
+
+
+/**
+ * SHFL_FN_WRITE
+ */
+
+/** Parameters structure. */
+typedef struct _VBoxSFWrite
+{
+ VBoxGuestHGCMCallInfo 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:
+ * Offset to write to.
+ */
+ 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)
+
+
+
+/**
+ * SHFL_FN_LOCK
+ */
+
+/** 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
+{
+ VBoxGuestHGCMCallInfo 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)
+
+
+
+/**
+ * SHFL_FN_FLUSH
+ */
+
+/** Parameters structure. */
+typedef struct _VBoxSFFlush
+{
+ VBoxGuestHGCMCallInfo 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)
+
+/**
+ * SHFL_FN_LIST
+ */
+
+/** 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
+
+/** Parameters structure. */
+typedef struct _VBoxSFList
+{
+ VBoxGuestHGCMCallInfo 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)
+
+
+
+/**
+ * SHFL_FN_READLINK
+ */
+
+/** Parameters structure. */
+typedef struct _VBoxSFReadLink
+{
+ VBoxGuestHGCMCallInfo 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.
+ */
+ HGCMFunctionParameter buffer;
+
+} VBoxSFReadLink;
+
+/** Number of parameters */
+#define SHFL_CPARMS_READLINK (3)
+
+
+
+/**
+ * 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 */
+
+
+/** Parameters structure. */
+typedef struct _VBoxSFInformation
+{
+ VBoxGuestHGCMCallInfo 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)
+
+
+/**
+ * SHFL_FN_REMOVE
+ */
+
+#define SHFL_REMOVE_FILE (0x1)
+#define SHFL_REMOVE_DIR (0x2)
+#define SHFL_REMOVE_SYMLINK (0x4)
+
+/** Parameters structure. */
+typedef struct _VBoxSFRemove
+{
+ VBoxGuestHGCMCallInfo 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)
+
+
+/**
+ * SHFL_FN_RENAME
+ */
+
+#define SHFL_RENAME_FILE (0x1)
+#define SHFL_RENAME_DIR (0x2)
+#define SHFL_RENAME_REPLACE_IF_EXISTS (0x4)
+
+/** Parameters structure. */
+typedef struct _VBoxSFRename
+{
+ VBoxGuestHGCMCallInfo 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)
+
+
+/**
+ * SHFL_FN_SYMLINK
+ */
+
+/** Parameters structure. */
+typedef struct _VBoxSFSymlink
+{
+ VBoxGuestHGCMCallInfo 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)
+
+
+
+/**
+ * SHFL_FN_ADD_MAPPING
+ * 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 (3)
+
+/**
+ * SHFL_FN_REMOVE_MAPPING
+ * Host call, no guest structure is used.
+ */
+
+#define SHFL_CPARMS_REMOVE_MAPPING (1)
+
+
+/**
+ * SHFL_FN_SET_STATUS_LED
+ * Host call, no guest structure is used.
+ */
+
+#define SHFL_CPARMS_SET_STATUS_LED (1)
+
+/** @} */
+
+#endif
--- /dev/null
+/** @file
+ * VirtualBox - Types.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___VBox_types_h
+#define ___VBox_types_h
+
+#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 VM. */
+typedef struct VM *PVM;
+/** 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 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;
+
+/** 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)
+
+
+/** 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. */
+typedef struct PDMDEVINS *PPDMDEVINS;
+/** Pointer to a pointer to a PDM Device Instance. */
+typedef PPDMDEVINS *PPPDMDEVINS;
+/** R3 pointer to a PDM Device Instance. */
+typedef R3PTRTYPE(PPDMDEVINS) PPDMDEVINSR3;
+/** R0 pointer to a PDM Device Instance. */
+typedef R0PTRTYPE(PPDMDEVINS) PPDMDEVINSR0;
+/** RC pointer to a PDM Device Instance. */
+typedef RCPTRTYPE(PPDMDEVINS) PPDMDEVINSRC;
+
+/** Pointer to a PDM PCI device structure. */
+typedef struct PDMPCIDEV *PPDMPCIDEV;
+
+/** 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;
+
+/** 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;
+
+/** 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 CPU context core. */
+typedef struct CPUMCTXCORE *PCPUMCTXCORE;
+/** Pointer to a const CPU context core. */
+typedef const struct CPUMCTXCORE *PCCPUMCTXCORE;
+
+/** 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;
+
+/** @} */
+
+
+/** @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.
+ */
+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. */
+typedef PDMNETWORKGSO *PPDMNETWORKGSO;
+/** Pointer to a const GSO context. */
+typedef PDMNETWORKGSO const *PCPDMNETWORKGSO;
+
+
+/**
+ * The current ROM page protection.
+ *
+ * @remarks This is part of the saved state.
+ */
+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.
+ */
+typedef struct PGMPAGEMAPLOCK
+{
+#if defined(IN_RC) || defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0)
+ /** 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. */
+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;
+
+
+/** @} */
+
+#endif
--- /dev/null
+/** @file
+ * VBox Version Management.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___VBox_version_h
+#define ___VBox_version_h
+
+/* 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
+
--- /dev/null
+/* $Id: assert.h $ */
+/** @file
+ * IPRT - Internal RTAssert header
+ */
+
+/*
+ * Copyright (C) 2009-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___internal_assert_h
+#define ___internal_assert_h
+
+#include <iprt/types.h>
+
+RT_C_DECLS_BEGIN
+
+#ifdef IN_RING0
+
+/**
+ * Print the 1st part of an assert message to whatever native facility is best
+ * fitting.
+ *
+ * @param pszExpr Expression. Can be NULL.
+ * @param uLine Location line number.
+ * @param pszFile Location file name.
+ * @param pszFunction Location function name.
+ */
+DECLHIDDEN(void) rtR0AssertNativeMsg1(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction);
+
+/**
+ * Print the 2nd (optional) part of an assert message to whatever native
+ * facility is best fitting.
+ *
+ * @param fInitial Whether it's the initial (true) or an additional (false)
+ * message.
+ * @param pszFormat Printf like format string.
+ * @param va Arguments to that string.
+ */
+DECLHIDDEN(void) rtR0AssertNativeMsg2V(bool fInitial, const char *pszFormat, va_list va);
+
+#endif
+
+RT_C_DECLS_END
+
+#endif
+
--- /dev/null
+/* $Id: initterm.h $ */
+/** @file
+ * IPRT - Initialization & Termination.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___internal_initterm_h
+#define ___internal_initterm_h
+
+#include <iprt/cdefs.h>
+
+RT_C_DECLS_BEGIN
+
+#ifdef IN_RING0
+
+/**
+ * Platform specific initialization.
+ *
+ * @returns IPRT status code.
+ */
+DECLHIDDEN(int) rtR0InitNative(void);
+
+/**
+ * Platform specific termination.
+ */
+DECLHIDDEN(void) rtR0TermNative(void);
+
+#endif /* IN_RING0 */
+
+RT_C_DECLS_END
+
+#endif
+
--- /dev/null
+/* $Id: iprt.h $ */
+/** @file
+ * IPRT - Internal header for miscellaneous global defs and types.
+ */
+
+/*
+ * Copyright (C) 2009-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___internal_iprt_h
+#define ___internal_iprt_h
+
+#include <iprt/cdefs.h>
+#include <iprt/types.h>
+
+/** @def RT_EXPORT_SYMBOL
+ * This define is really here just for the linux kernel.
+ * @param Name The symbol name.
+ */
+#if defined(RT_OS_LINUX) \
+ && defined(IN_RING0) \
+ && defined(MODULE) \
+ && !defined(RT_NO_EXPORT_SYMBOL)
+# define bool linux_bool /* see r0drv/linux/the-linux-kernel.h */
+# 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
+# if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
+# define MODVERSIONS
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 71)
+# include <linux/modversions.h>
+# endif
+# endif
+# include <linux/module.h>
+# undef bool
+# define RT_EXPORT_SYMBOL(Name) EXPORT_SYMBOL(Name)
+#else
+# define RT_EXPORT_SYMBOL(Name) extern int g_rtExportSymbolDummyVariable
+#endif
+
+
+/** @def RT_MORE_STRICT
+ * Enables more assertions in IPRT. */
+#if !defined(RT_MORE_STRICT) && (defined(DEBUG) || defined(RT_STRICT) || defined(DOXYGEN_RUNNING)) && !defined(RT_OS_WINDOWS) /** @todo enable on windows after testing */
+# define RT_MORE_STRICT
+#endif
+
+/** @def RT_ASSERT_PREEMPT_CPUID_VAR
+ * Partner to RT_ASSERT_PREEMPT_CPUID_VAR. Declares and initializes a variable
+ * idAssertCpu to NIL_RTCPUID if preemption is enabled and to RTMpCpuId if
+ * disabled. When RT_MORE_STRICT isn't defined it declares an uninitialized
+ * dummy variable.
+ *
+ * Requires iprt/mp.h and iprt/asm.h.
+ */
+/** @def RT_ASSERT_PREEMPT_CPUID
+ * Asserts that we didn't change CPU since RT_ASSERT_PREEMPT_CPUID_VAR if
+ * preemption is disabled. Will also detect changes in preemption
+ * disable/enable status. This is a noop when RT_MORE_STRICT isn't defined. */
+#ifdef RT_MORE_STRICT
+# define RT_ASSERT_PREEMPT_CPUID_VAR() \
+ RTCPUID const idAssertCpu = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId()
+# define RT_ASSERT_PREEMPT_CPUID() \
+ do \
+ { \
+ RTCPUID const idAssertCpuNow = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId(); \
+ AssertMsg(idAssertCpu == idAssertCpuNow, ("%#x, %#x\n", idAssertCpu, idAssertCpuNow)); \
+ } while (0)
+
+#else
+# define RT_ASSERT_PREEMPT_CPUID_VAR() RTCPUID idAssertCpuDummy
+# define RT_ASSERT_PREEMPT_CPUID() NOREF(idAssertCpuDummy)
+#endif
+
+/** @def RT_ASSERT_PREEMPT_CPUID_SPIN_ACQUIRED
+ * Extended version of RT_ASSERT_PREEMPT_CPUID for use before
+ * RTSpinlockAcquired* returns. This macro works the idCpuOwner and idAssertCpu
+ * members of the spinlock instance data. */
+#ifdef RT_MORE_STRICT
+# define RT_ASSERT_PREEMPT_CPUID_SPIN_ACQUIRED(pThis) \
+ do \
+ { \
+ RTCPUID const idAssertCpuNow = RTMpCpuId(); \
+ AssertMsg(idAssertCpu == idAssertCpuNow || idAssertCpu == NIL_RTCPUID, ("%#x, %#x\n", idAssertCpu, idAssertCpuNow)); \
+ (pThis)->idAssertCpu = idAssertCpu; \
+ (pThis)->idCpuOwner = idAssertCpuNow; \
+ } while (0)
+#else
+# define RT_ASSERT_PREEMPT_CPUID_SPIN_ACQUIRED(pThis) NOREF(idAssertCpuDummy)
+#endif
+
+/** @def RT_ASSERT_PREEMPT_CPUID_SPIN_RELEASE_VARS
+ * Extended version of RT_ASSERT_PREEMPT_CPUID_VAR for use with
+ * RTSpinlockRelease* returns. */
+#ifdef RT_MORE_STRICT
+# define RT_ASSERT_PREEMPT_CPUID_SPIN_RELEASE_VARS() RTCPUID idAssertCpu
+#else
+# define RT_ASSERT_PREEMPT_CPUID_SPIN_RELEASE_VARS() RTCPUID idAssertCpuDummy
+#endif
+
+/** @def RT_ASSERT_PREEMPT_CPUID_SPIN_RELEASE
+ * Extended version of RT_ASSERT_PREEMPT_CPUID for use in RTSpinlockRelease*
+ * before calling the native API for releasing the spinlock. It must be
+ * teamed up with RT_ASSERT_PREEMPT_CPUID_SPIN_ACQUIRED. */
+#ifdef RT_MORE_STRICT
+# define RT_ASSERT_PREEMPT_CPUID_SPIN_RELEASE(pThis) \
+ do \
+ { \
+ RTCPUID const idCpuOwner = (pThis)->idCpuOwner; \
+ RTCPUID const idAssertCpuNow = RTMpCpuId(); \
+ AssertMsg(idCpuOwner == idAssertCpuNow, ("%#x, %#x\n", idCpuOwner, idAssertCpuNow)); \
+ (pThis)->idCpuOwner = NIL_RTCPUID; \
+ idAssertCpu = (pThis)->idAssertCpu; \
+ (pThis)->idAssertCpu = NIL_RTCPUID; \
+ } while (0)
+#else
+# define RT_ASSERT_PREEMPT_CPUID_SPIN_RELEASE(pThis) NOREF(idAssertCpuDummy)
+#endif
+
+/** @def RT_ASSERT_PREEMPT_CPUID_DISABLE
+ * For use in RTThreadPreemptDisable implementations after having disabled
+ * preemption. Requires iprt/mp.h. */
+#ifdef RT_MORE_STRICT
+# define RT_ASSERT_PREEMPT_CPUID_DISABLE(pStat) \
+ do \
+ { \
+ Assert((pStat)->idCpu == NIL_RTCPUID); \
+ (pStat)->idCpu = RTMpCpuId(); \
+ } while (0)
+#else
+# define RT_ASSERT_PREEMPT_CPUID_DISABLE(pStat) \
+ Assert((pStat)->idCpu == NIL_RTCPUID)
+#endif
+
+/** @def RT_ASSERT_PREEMPT_CPUID_RESTORE
+ * For use in RTThreadPreemptRestore implementations before restoring
+ * preemption. Requires iprt/mp.h. */
+#ifdef RT_MORE_STRICT
+# define RT_ASSERT_PREEMPT_CPUID_RESTORE(pStat) \
+ do \
+ { \
+ RTCPUID const idAssertCpuNow = RTMpCpuId(); \
+ AssertMsg((pStat)->idCpu == idAssertCpuNow, ("%#x, %#x\n", (pStat)->idCpu, idAssertCpuNow)); \
+ (pStat)->idCpu = NIL_RTCPUID; \
+ } while (0)
+#else
+# define RT_ASSERT_PREEMPT_CPUID_RESTORE(pStat) do { } while (0)
+#endif
+
+
+/** @def RT_ASSERT_INTS_ON
+ * Asserts that interrupts are disabled when RT_MORE_STRICT is defined. */
+#ifdef RT_MORE_STRICT
+# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
+# define RT_ASSERT_INTS_ON() Assert(ASMIntAreEnabled())
+# else /* PORTME: Add architecture/platform specific test. */
+# define RT_ASSERT_INTS_ON() Assert(RTThreadPreemptIsEnabled(NIL_RTTHREAD))
+# endif
+#else
+# define RT_ASSERT_INTS_ON() do { } while (0)
+#endif
+
+/** @def RT_ASSERT_PREEMPTIBLE
+ * Asserts that preemption hasn't been disabled (using
+ * RTThreadPreemptDisable) when RT_MORE_STRICT is defined. */
+#ifdef RT_MORE_STRICT
+# define RT_ASSERT_PREEMPTIBLE() Assert(RTThreadPreemptIsEnabled(NIL_RTTHREAD))
+#else
+# define RT_ASSERT_PREEMPTIBLE() do { } while (0)
+#endif
+
+
+RT_C_DECLS_BEGIN
+
+#ifdef RT_OS_OS2
+uint32_t rtR0SemWaitOs2ConvertTimeout(uint32_t fFlags, uint64_t uTimeout);
+#endif
+
+RT_C_DECLS_END
+
+#endif
+
--- /dev/null
+/* $Id: lockvalidator.h $ */
+/** @file
+ * IPRT - Internal RTLockValidator header.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_internal_lockvalidator_h
+#define ___iprt_internal_lockvalidator_h
+
+#include <iprt/types.h>
+#include <iprt/lockvalidator.h>
+
+RT_C_DECLS_BEGIN
+
+
+/**
+ * Record used only on the lock stack for recording the stack and source
+ * position of a recursive lock acquisition.
+ */
+typedef struct RTLOCKVALRECNEST
+{
+ RTLOCKVALRECCORE Core;
+ /** The recursion level at this point in the stack. */
+ uint32_t cRecursion;
+ /** Pointer to the next record on the stack. */
+ PRTLOCKVALRECUNION volatile pDown;
+ /** Pointer to the first recursion. */
+ PRTLOCKVALRECUNION volatile pRec;
+ /** Pointer to the next free record when in the
+ * RTLOCKVALPERTHREAD::pFreeNestRecs list. */
+ struct RTLOCKVALRECNEST *pNextFree;
+ /** The source position. */
+ RTLOCKVALSRCPOS SrcPos;
+} RTLOCKVALRECNEST;
+/** Pointer to a recursion record. */
+typedef RTLOCKVALRECNEST *PRTLOCKVALRECNEST;
+
+
+/**
+ * Record union for simplifying internal processing.
+ */
+typedef union RTLOCKVALRECUNION
+{
+ RTLOCKVALRECCORE Core;
+ RTLOCKVALRECEXCL Excl;
+ RTLOCKVALRECSHRD Shared;
+ RTLOCKVALRECSHRDOWN ShrdOwner;
+ RTLOCKVALRECNEST Nest;
+} RTLOCKVALRECUNION;
+
+
+/**
+ * Per thread data for the lock validator.
+ *
+ * This is part of the RTTHREADINT structure.
+ */
+typedef struct RTLOCKVALPERTHREAD
+{
+ /** Where we are blocking. */
+ RTLOCKVALSRCPOS SrcPos;
+ /** Top of the lock stack. */
+ PRTLOCKVALRECUNION volatile pStackTop;
+ /** List of free recursion (nesting) record. */
+ PRTLOCKVALRECNEST pFreeNestRecs;
+ /** What we're blocking on.
+ * The lock validator sets this, RTThreadUnblock clears it. */
+ PRTLOCKVALRECUNION volatile pRec;
+ /** The state in which pRec that goes with pRec.
+ * RTThreadUnblocking uses this to figure out when to clear pRec. */
+ RTTHREADSTATE volatile enmRecState;
+ /** The thread is running inside the lock validator. */
+ bool volatile fInValidator;
+ /** Reserved for alignment purposes. */
+ bool afReserved[3];
+ /** Number of registered write locks, mutexes and critsects that this thread owns. */
+ int32_t volatile cWriteLocks;
+ /** Number of registered read locks that this thread owns, nesting included. */
+ int32_t volatile cReadLocks;
+ /** Bitmap indicating which entires are free (set) and allocated (clear). */
+ uint32_t volatile bmFreeShrdOwners;
+ /** Reserved for alignment purposes. */
+ uint32_t u32Reserved;
+ /** Statically allocated shared owner records */
+ RTLOCKVALRECSHRDOWN aShrdOwners[32];
+} RTLOCKVALPERTHREAD;
+
+
+DECLHIDDEN(void) rtLockValidatorInitPerThread(RTLOCKVALPERTHREAD *pPerThread);
+DECLHIDDEN(void) rtLockValidatorDeletePerThread(RTLOCKVALPERTHREAD *pPerThread);
+DECLHIDDEN(void) rtLockValidatorSerializeDestructEnter(void);
+DECLHIDDEN(void) rtLockValidatorSerializeDestructLeave(void);
+
+RT_C_DECLS_END
+
+#endif
+
--- /dev/null
+/* $Id: magics.h $ */
+/** @file
+ * IPRT - Internal header defining The Magic Numbers.
+ */
+
+/*
+ * Copyright (C) 2007-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___internal_magics_h
+#define ___internal_magics_h
+
+/** @name Magic Numbers.
+ * @{ */
+
+/** Magic number for RTAIOMGRINT::u32Magic. (Emil Erich Kaestner) */
+#define RTAIOMGR_MAGIC UINT32_C(0x18990223)
+/** Magic number for RTAIOMGRINTFILE::u32Magic. (Ephraim Kishon) */
+#define RTAIOMGRFILE_MAGIC UINT32_C(0x19240823)
+/** Magic number for RTDBGMODINT::u32Magic. (Charles Lloyd) */
+#define RTDBGAS_MAGIC UINT32_C(0x19380315)
+/** Magic number for RTDBGCFGINT::u32Magic. (McCoy Tyner) */
+#define RTDBGCFG_MAGIC UINT32_C(0x19381211)
+/** Magic number for RTDBGMODINT::u32Magic. (Keith Jarrett) */
+#define RTDBGMOD_MAGIC UINT32_C(0x19450508)
+/** Magic number for RTDBGMODVTIMG::u32Magic. (Jack DeJohnette) */
+#define RTDBGMODVTDBG_MAGIC UINT32_C(0x19420809)
+/** Magic number for RTDBGMODVTIMG::u32Magic. (Cecil McBee) */
+#define RTDBGMODVTIMG_MAGIC UINT32_C(0x19350419)
+/** Magic value for RTDBGKRNLINFOINT::u32Magic. (John Carmack) */
+#define RTDBGKRNLINFO_MAGIC UINT32_C(0x19700820)
+/** The value of RTDIR::u32Magic. (Michael Ende) */
+#define RTDIR_MAGIC UINT32_C(0x19291112)
+/** The value of RTDIR::u32Magic after RTDirClose(). */
+#define RTDIR_MAGIC_DEAD UINT32_C(0x19950829)
+/** The value of RTDVMINTERNAL::u32Magic. (Dan Brown) */
+#define RTDVM_MAGIC UINT32_C(0x19640622)
+/** The value of RTDVMINTERNAL::u32Magic after close. */
+#define RTDVM_MAGIC_DEAD (~RTDVM_MAGIC)
+/** The value of RTDVMVOLUMEINTERNAL::u32Magic. (Daniel Defoe) */
+#define RTDVMVOLUME_MAGIC UINT32_C(0x16591961)
+/** The value of RTDVMVOLUMEINTERNAL::u32Magic after close. */
+#define RTDVMVOLUME_MAGIC_DEAD UINT32_C(0x17310424)
+/** The value of RTFILEAIOCTXINT::u32Magic. (Howard Phillips Lovecraft) */
+#define RTFILEAIOCTX_MAGIC UINT32_C(0x18900820)
+/** The value of RTFILEAIOCTXINT::u32Magic after RTFileAioCtxDestroy(). */
+#define RTFILEAIOCTX_MAGIC_DEAD UINT32_C(0x19370315)
+/** The value of RTFILEAIOREQINT::u32Magic. (Stephen Edwin King) */
+#define RTFILEAIOREQ_MAGIC UINT32_C(0x19470921)
+/** The value of RTENVINTERNAL::u32Magic. (Rumiko Takahashi) */
+#define RTENV_MAGIC UINT32_C(0x19571010)
+/** The value of RTERRVARS::ai32Vars[0]. (Ryuichi Sakamoto) */
+#define RTERRVARS_MAGIC UINT32_C(0x19520117)
+/** Magic number for RTHANDLETABLEINT::u32Magic. (Hitomi Kanehara) */
+#define RTHANDLETABLE_MAGIC UINT32_C(0x19830808)
+/** Magic number for RTHEAPOFFSETINTERNAL::u32Magic. (Neal Town Stephenson) */
+#define RTHEAPOFFSET_MAGIC UINT32_C(0x19591031)
+/** Magic number for RTHEAPSIMPLEINTERNAL::uMagic. (Kyoichi Katayama) */
+#define RTHEAPSIMPLE_MAGIC UINT32_C(0x19590105)
+/** The magic value for RTHTTPINTERNAL::u32Magic. (Karl May) */
+#define RTHTTP_MAGIC UINT32_C(0x18420225)
+/** The value of RTHTTPINTERNAL::u32Magic after close. */
+#define RTHTTP_MAGIC_DEAD UINT32_C(0x19120330)
+/** The magic value for RTLDRMODINTERNAL::u32Magic. (Alan Moore) */
+#define RTLDRMOD_MAGIC UINT32_C(0x19531118)
+/** The magic value for RTLOCALIPCSERVER::u32Magic. (Naoki Yamamoto) */
+#define RTLOCALIPCSERVER_MAGIC UINT32_C(0x19600201)
+/** The magic value for RTLOCALIPCSERVER::u32Magic. (Katsuhiro Otomo) */
+#define RTLOCALIPCSESSION_MAGIC UINT32_C(0x19530414)
+/** The magic value for RTLOCKVALCLASSINT::u32Magic. (Thomas Mann) */
+#define RTLOCKVALCLASS_MAGIC UINT32_C(0x18750605)
+/** The magic value for RTLOCKVALCLASSINT::u32Magic after destruction. */
+#define RTLOCKVALCLASS_MAGIC_DEAD UINT32_C(0x19550812)
+/** The magic value for RTLOCKVALRECEXCL::u32Magic. (Vladimir Vladimirovich Nabokov) */
+#define RTLOCKVALRECEXCL_MAGIC UINT32_C(0x18990422)
+/** The dead magic value for RTLOCKVALRECEXCL::u32Magic. */
+#define RTLOCKVALRECEXCL_MAGIC_DEAD UINT32_C(0x19770702)
+/** The magic value for RTLOCKVALRECSHRD::u32Magic. (Agnar Mykle) */
+#define RTLOCKVALRECSHRD_MAGIC UINT32_C(0x19150808)
+/** The magic value for RTLOCKVALRECSHRD::u32Magic after deletion. */
+#define RTLOCKVALRECSHRD_MAGIC_DEAD UINT32_C(0x19940115)
+/** The magic value for RTLOCKVALRECSHRDOWN::u32Magic. (Jens Ingvald Bjoerneboe) */
+#define RTLOCKVALRECSHRDOWN_MAGIC UINT32_C(0x19201009)
+/** The magic value for RTLOCKVALRECSHRDOWN::u32Magic after deletion. */
+#define RTLOCKVALRECSHRDOWN_MAGIC_DEAD UINT32_C(0x19760509)
+/** The magic value for RTLOCKVALRECNEST::u32Magic. (Anne Desclos) */
+#define RTLOCKVALRECNEST_MAGIC UINT32_C(0x19071123)
+/** The magic value for RTLOCKVALRECNEST::u32Magic after deletion. */
+#define RTLOCKVALRECNEST_MAGIC_DEAD UINT32_C(0x19980427)
+/** Magic number for RTMEMCACHEINT::u32Magic. (Joseph Weizenbaum) */
+#define RTMEMCACHE_MAGIC UINT32_C(0x19230108)
+/** Dead magic number for RTMEMCACHEINT::u32Magic. */
+#define RTMEMCACHE_MAGIC_DEAD UINT32_C(0x20080305)
+/** The magic value for RTMEMPOOL::u32Magic. (Jane Austin) */
+#define RTMEMPOOL_MAGIC UINT32_C(0x17751216)
+/** The magic value for RTMEMPOOL::u32Magic after RTMemPoolDestroy. */
+#define RTMEMPOOL_MAGIC_DEAD UINT32_C(0x18170718)
+/** The magic value for heap blocks. (Edgar Allan Poe) */
+#define RTMEMHDR_MAGIC UINT32_C(0x18090119)
+/** The magic value for heap blocks after freeing. */
+#define RTMEMHDR_MAGIC_DEAD UINT32_C(0x18491007)
+/** The value of RTPIPEINTERNAL::u32Magic. (Frank Schaetzing) */
+#define RTPIPE_MAGIC UINT32_C(0x19570528)
+/** The value of RTPOLLSETINTERNAL::u32Magic. (Ai Yazawa) */
+#define RTPOLLSET_MAGIC UINT32_C(0x19670307)
+/** RTR0MEMOBJ::u32Magic. (Masakazu Katsura) */
+#define RTR0MEMOBJ_MAGIC UINT32_C(0x19611210)
+/** RTRANDINT::u32Magic. (Alan Moore) */
+#define RTRANDINT_MAGIC UINT32_C(0x19531118)
+/** The value of RTREQ::u32Magic. */
+#define RTREQ_MAGIC UINT32_C(0xfeed0001) /**< @todo find a value */
+/** The value of RTREQ::u32Magic of a freed request. */
+#define RTREQ_MAGIC_DEAD (~RTREQ_MAGIC)
+/** The value of RTREQPOOLINT::u32Magic. */
+#define RTREQPOOL_MAGIC UINT32_C(0xfeed0002)/**< @todo find a value */
+/** The value of RTREQPOOLINT::u32Magic after destruction. */
+#define RTREQPOOL_MAGIC_DEAD (~RTREQPOOL_MAGIC)
+/** The value of RTREQQUEUEINT::u32Magic. */
+#define RTREQQUEUE_MAGIC UINT32_C(0xfeed0003)/**< @todo find a value */
+/** The value of RTREQQUEUEINT::u32Magic after destruction. */
+#define RTREQQUEUE_MAGIC_DEAD (~RTREQQUEUE_MAGIC)
+/** The value of RTS3::u32Magic. (Edgar Wallace) */
+#define RTS3_MAGIC UINT32_C(0x18750401)
+/** The value of RTS3::u32Magic after RTS3Destroy(). */
+#define RTS3_MAGIC_DEAD UINT32_C(0x19320210)
+/** Magic for the event semaphore structure. (Neil Gaiman) */
+#define RTSEMEVENT_MAGIC UINT32_C(0x19601110)
+/** Magic for the multiple release event semaphore structure. (Isaac Asimov) */
+#define RTSEMEVENTMULTI_MAGIC UINT32_C(0x19200102)
+/** Dead magic value for multiple release event semaphore structures. */
+#define RTSEMEVENTMULTI_MAGIC_DEAD UINT32_C(0x19920406)
+/** Magic value for RTSEMFASTMUTEXINTERNAL::u32Magic. (John Ronald Reuel Tolkien) */
+#define RTSEMFASTMUTEX_MAGIC UINT32_C(0x18920103)
+/** Dead magic value for RTSEMFASTMUTEXINTERNAL::u32Magic. */
+#define RTSEMFASTMUTEX_MAGIC_DEAD UINT32_C(0x19730902)
+/** Magic for the mutex semaphore structure. (Douglas Adams) */
+#define RTSEMMUTEX_MAGIC UINT32_C(0x19520311)
+/** Dead magic for the mutex semaphore structure. */
+#define RTSEMMUTEX_MAGIC_DEAD UINT32_C(0x20010511)
+/** Magic for the spinning mutex semaphore structure. (Natsume Soseki) */
+#define RTSEMSPINMUTEX_MAGIC UINT32_C(0x18670209)
+/** Dead magic value for RTSEMSPINMUTEXINTERNAL::u32Magic. */
+#define RTSEMSPINMUTEX_MAGIC_DEAD UINT32_C(0x19161209)
+/** RTSEMRWINTERNAL::u32Magic value. (Kosuke Fujishima) */
+#define RTSEMRW_MAGIC UINT32_C(0x19640707)
+/** RTSEMXROADSINTERNAL::u32Magic value. (Kenneth Elton "Ken" Kesey) */
+#define RTSEMXROADS_MAGIC UINT32_C(0x19350917)
+/** RTSEMXROADSINTERNAL::u32Magic value after RTSemXRoadsDestroy. */
+#define RTSEMXROADS_MAGIC_DEAD UINT32_C(0x20011110)
+/** The magic value for RTSOCKETINT::u32Magic. (Stanislaw Lem) */
+#define RTSOCKET_MAGIC UINT32_C(0x19210912)
+/** The magic value for RTSOCKETINT::u32Magic after destruction. */
+#define RTSOCKET_MAGIC_DEAD UINT32_C(0x20060326)
+/** Magic value for RTSPINLOCKINTERNAL::u32Magic. (Terry Pratchett) */
+#define RTSPINLOCK_MAGIC UINT32_C(0x19480428)
+/** Magic value for generic RTSPINLOCKINTERNAL::u32Magic (Georges Prosper Remi). */
+#define RTSPINLOCK_GEN_MAGIC UINT32_C(0x10970522)
+/** Magic value for RTSTRCACHE::u32Magic. (Sir Arthur Charles Clarke) */
+#define RTSTRCACHE_MAGIC UINT32_C(0x19171216)
+/** Magic value for RTSTRCACHE::u32Magic after RTStrCacheDestroy. */
+#define RTSTRCACHE_MAGIC_DEAD UINT32_C(0x20080319)
+/** The value of RTSTREAM::u32Magic for a valid stream. */
+#define RTSTREAM_MAGIC UINT32_C(0xe44e44ee)
+/** Magic value for RTTCPSERVER::u32Magic. (Jan Garbarek) */
+#define RTTCPSERVER_MAGIC UINT32_C(0x19470304)
+/** Magic value for RTTCPSERVER::u32Magic. (Harlan Ellison) */
+#define RTUDPSERVER_MAGIC UINT32_C(0x19340527)
+/** The value of RTTAR::u32Magic. (Donald Ervin Knuth) */
+#define RTTAR_MAGIC UINT32_C(0x19380110)
+/** The value of RTTAR::u32Magic after RTTarClose(). */
+#define RTTAR_MAGIC_DEAD ~RTTAR_MAGIC
+/** The value of RTTARFILE::u32Magic. (Abraham Stoker) */
+#define RTTARFILE_MAGIC UINT32_C(0x18471108)
+/** The value of RTTARFILE::u32Magic after RTTarFileClose(). */
+#define RTTARFILE_MAGIC_DEAD UINT32_C(0x19120420)
+/** RTTESTINT::u32Magic value. (Daniel Kehlmann) */
+#define RTTESTINT_MAGIC UINT32_C(0x19750113)
+/** RTTHREADCTXHOOKINT::u32Magic value. (Dennis MacAlistair Ritchie) */
+#define RTTHREADCTXHOOKINT_MAGIC UINT32_C(0x19410909)
+/** RTTHREADINT::u32Magic value. (Gilbert Keith Chesterton) */
+#define RTTHREADINT_MAGIC UINT32_C(0x18740529)
+/** RTTHREADINT::u32Magic value for a dead thread. */
+#define RTTHREADINT_MAGIC_DEAD UINT32_C(0x19360614)
+/** Magic number for timer handles. (Jared Mason Diamond) */
+#define RTTIMER_MAGIC UINT32_C(0x19370910)
+/** Magic number for timer low resolution handles. (Saki Hiwatari) */
+#define RTTIMERLR_MAGIC UINT32_C(0x19610715)
+/** Magic value of RTTRACEBUFINT::u32Magic. (George Orwell) */
+#define RTTRACEBUF_MAGIC UINT32_C(0x19030625)
+/** Magic value of RTTRACEBUFINT::u32Magic after the final release. */
+#define RTTRACEBUF_MAGIC_DEAD UINT32_C(0x19500121)
+/** The value of RTVFSOBJINTERNAL::u32Magic. (Yasunari Kawabata) */
+#define RTVFSOBJ_MAGIC UINT32_C(0x18990614)
+/** The value of RTVFSOBJINTERNAL::u32Magic arter close. */
+#define RTVFSOBJ_MAGIC_DEAD UINT32_C(0x19720416)
+/** The value of RTVFSINTERNAL::u32Magic. (Sir Kingsley William Amis) */
+#define RTVFS_MAGIC UINT32_C(0x19220416)
+/** The value of RTVFSINTERNAL::u32Magic after close. */
+#define RTVFS_MAGIC_DEAD UINT32_C(0x19951022)
+/** The value of RTVFSFSSTREAMINTERNAL::u32Magic. (William McGuire "Bill" Bryson) */
+#define RTVFSFSSTREAM_MAGIC UINT32_C(0x19511208)
+/** The value of RTVFSFSSTREAMINTERNAL::u32Magic after close */
+#define RTVFSFSSTREAM_MAGIC_DEAD (~RTVFSFSSTREAM_MAGIC)
+/** The value of RTVFSDIRINTERNAL::u32Magic. (Franklin Patrick Herbert, Jr.) */
+#define RTVFSDIR_MAGIC UINT32_C(0x19201008)
+/** The value of RTVFSDIRINTERNAL::u32Magic after close. */
+#define RTVFSDIR_MAGIC_DEAD UINT32_C(0x19860211)
+/** The value of RTVFSFILEINTERNAL::u32Magic. (Charles John Huffam Dickens) */
+#define RTVFSFILE_MAGIC UINT32_C(0x18120207)
+/** The value of RTVFSFILEINTERNAL::u32Magic after close. */
+#define RTVFSFILE_MAGIC_DEAD UINT32_C(0x18700609)
+/** The value of RTVFSIOSTREAMINTERNAL::u32Magic. (Ernest Miller Hemingway) */
+#define RTVFSIOSTREAM_MAGIC UINT32_C(0x18990721)
+/** The value of RTVFSIOSTREAMINTERNAL::u32Magic after close. */
+#define RTVFSIOSTREAM_MAGIC_DEAD UINT32_C(0x19610702)
+/** The value of RTVFSSYMLINKINTERNAL::u32Magic. (Francis Scott Key Fitzgerald) */
+#define RTVFSSYMLINK_MAGIC UINT32_C(0x18960924)
+/** The value of RTVFSSYMLINKINTERNAL::u32Magic after close. */
+#define RTVFSSYMLINK_MAGIC_DEAD UINT32_C(0x19401221)
+
+/** @} */
+
+#endif
+
--- /dev/null
+/* $Id: mem.h $ */
+/** @file
+ * IPRT - Memory Management.
+ */
+
+/*
+ * Copyright (C) 2010-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___internal_mem_h
+#define ___internal_mem_h
+
+#include <iprt/cdefs.h>
+
+RT_C_DECLS_BEGIN
+
+/**
+ * Special allocation method that does not have any IPRT dependencies.
+ *
+ * This is suitable for allocating memory for IPRT heaps, pools, caches, memory
+ * trackers, semaphores and similar that end up in bootstrap depencency hell
+ * otherwise.
+ *
+ * @returns Pointer to the allocated memory, NULL on failure. Must be freed by
+ * calling rtMemBaseFree().
+ * @param cb The number of bytes to allocate.
+ */
+DECLHIDDEN(void *) rtMemBaseAlloc(size_t cb);
+
+/**
+ * Frees memory allocated by rtInitAlloc().
+ *
+ * @param pv What rtInitAlloc() returned.
+ */
+DECLHIDDEN(void) rtMemBaseFree(void *pv);
+
+
+#ifdef IN_RING0
+/** @def RTR0MEM_WITH_EF_APIS
+ * Enables the electrict fence APIs.
+ *
+ * Requires working rtR0MemObjNativeProtect implementation, thus the current
+ * OS restrictions.
+ */
+# if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) || defined(DOXYGEN_RUNNING)
+# define RTR0MEM_WITH_EF_APIS
+# endif
+# ifdef RTR0MEM_WITH_EF_APIS
+DECLHIDDEN(void) rtR0MemEfInit(void);
+DECLHIDDEN(void) rtR0MemEfTerm(void);
+# endif
+#endif
+
+RT_C_DECLS_END
+
+#endif
+
--- /dev/null
+/* $Id: memobj.h $ */
+/** @file
+ * IPRT - Ring-0 Memory Objects.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___internal_memobj_h
+#define ___internal_memobj_h
+
+#include <iprt/memobj.h>
+#include <iprt/assert.h>
+#include "internal/magics.h"
+
+RT_C_DECLS_BEGIN
+
+/** @defgroup grp_rt_memobj_int Internals.
+ * @ingroup grp_rt_memobj
+ * @internal
+ * @{
+ */
+
+/**
+ * Ring-0 memory object type.
+ */
+typedef enum RTR0MEMOBJTYPE
+{
+ /** The traditional invalid value. */
+ RTR0MEMOBJTYPE_INVALID = 0,
+
+ /** @name Primary types (parents)
+ * @{ */
+ /** RTR0MemObjAllocPage.
+ * This memory is page aligned and fixed. */
+ RTR0MEMOBJTYPE_PAGE,
+ /** RTR0MemObjAllocLow.
+ * This memory is page aligned, fixed and is backed by physical memory below 4GB. */
+ RTR0MEMOBJTYPE_LOW,
+ /** RTR0MemObjAllocCont.
+ * This memory is page aligned, fixed and is backed by contiguous physical memory below 4GB. */
+ RTR0MEMOBJTYPE_CONT,
+ /** RTR0MemObjLockKernel, RTR0MemObjLockUser.
+ * This memory is page aligned and fixed. It was locked/pinned/wired down by the API call. */
+ RTR0MEMOBJTYPE_LOCK,
+ /** RTR0MemObjAllocPhys, RTR0MemObjEnterPhys.
+ * This memory is physical memory, page aligned, contiguous and doesn't need to have a mapping. */
+ RTR0MEMOBJTYPE_PHYS,
+ /** RTR0MemObjAllocPhysNC.
+ * This memory is physical memory, page aligned and doesn't need to have a mapping. */
+ RTR0MEMOBJTYPE_PHYS_NC,
+ /** RTR0MemObjReserveKernel, RTR0MemObjReserveUser.
+ * This memory is page aligned and has no backing. */
+ RTR0MEMOBJTYPE_RES_VIRT,
+ /** @} */
+
+ /** @name Secondary types (children)
+ * @{
+ */
+ /** RTR0MemObjMapUser, RTR0MemObjMapKernel.
+ * This is a user or kernel context mapping of another ring-0 memory object. */
+ RTR0MEMOBJTYPE_MAPPING,
+ /** @} */
+
+ /** The end of the valid types. Used for sanity checking. */
+ RTR0MEMOBJTYPE_END
+} RTR0MEMOBJTYPE;
+
+
+/** @name RTR0MEMOBJINTERNAL::fFlags
+ * @{ */
+/** Page level protection was changed. */
+#define RTR0MEMOBJ_FLAGS_PROT_CHANGED RT_BIT_32(0)
+/** @} */
+
+
+typedef struct RTR0MEMOBJINTERNAL *PRTR0MEMOBJINTERNAL;
+typedef struct RTR0MEMOBJINTERNAL **PPRTR0MEMOBJINTERNAL;
+
+/**
+ * Ring-0 memory object.
+ *
+ * When using the PRTR0MEMOBJINTERNAL and PPRTR0MEMOBJINTERNAL types
+ * we get pMem and ppMem variable names.
+ *
+ * When using the RTR0MEMOBJ and PRTR0MEMOBJ types we get MemObj and
+ * pMemObj variable names. We never dereference variables of the RTR0MEMOBJ
+ * type, we always convert it to a PRTR0MEMOBJECTINTERNAL variable first.
+ */
+typedef struct RTR0MEMOBJINTERNAL
+{
+ /** Magic number (RTR0MEMOBJ_MAGIC). */
+ uint32_t u32Magic;
+ /** The size of this structure. */
+ uint32_t cbSelf;
+ /** The type of allocation. */
+ RTR0MEMOBJTYPE enmType;
+ /** Flags, RTR0MEMOBJ_FLAGS_*. */
+ uint32_t fFlags;
+ /** The size of the memory allocated, pinned down, or mapped. */
+ size_t cb;
+ /** The memory address.
+ * What this really is varies with the type.
+ * For PAGE, CONT, LOW, RES_VIRT/R0, LOCK/R0 and MAP/R0 it's the ring-0 mapping.
+ * For LOCK/R3, RES_VIRT/R3 and MAP/R3 it is the ring-3 mapping.
+ * For PHYS this might actually be NULL if there isn't any mapping.
+ */
+ void *pv;
+
+ /** Object relations. */
+ union
+ {
+ /** This is for tracking child memory handles mapping the
+ * memory described by the primary handle. */
+ struct
+ {
+ /** Number of mappings. */
+ uint32_t cMappingsAllocated;
+ /** Number of mappings in the array. */
+ uint32_t cMappings;
+ /** Pointers to child handles mapping this memory. */
+ PPRTR0MEMOBJINTERNAL papMappings;
+ } Parent;
+
+ /** Pointer to the primary handle. */
+ struct
+ {
+ /** Pointer to the parent. */
+ PRTR0MEMOBJINTERNAL pParent;
+ } Child;
+ } uRel;
+
+ /** Type specific data for the memory types that requires that. */
+ union
+ {
+ /** RTR0MEMTYPE_PAGE. */
+ struct
+ {
+ unsigned iDummy;
+ } Page;
+
+ /** RTR0MEMTYPE_LOW. */
+ struct
+ {
+ unsigned iDummy;
+ } Low;
+
+ /** RTR0MEMTYPE_CONT. */
+ struct
+ {
+ /** The physical address of the first page. */
+ RTHCPHYS Phys;
+ } Cont;
+
+ /** RTR0MEMTYPE_LOCK_USER. */
+ struct
+ {
+ /** The process that owns the locked memory.
+ * This is NIL_RTR0PROCESS if it's kernel memory. */
+ RTR0PROCESS R0Process;
+ } Lock;
+
+ /** RTR0MEMTYPE_PHYS. */
+ struct
+ {
+ /** The base address of the physical memory. */
+ RTHCPHYS PhysBase;
+ /** If set this object was created by RTR0MemPhysAlloc, otherwise it was
+ * created by RTR0MemPhysEnter. */
+ bool fAllocated;
+ /** See RTMEM_CACHE_POLICY_XXX constants */
+ uint32_t uCachePolicy;
+ } Phys;
+
+ /** RTR0MEMTYPE_PHYS_NC. */
+ struct
+ {
+ unsigned iDummy;
+ } PhysNC;
+
+ /** RTR0MEMOBJTYPE_RES_VIRT */
+ struct
+ {
+ /** The process that owns the reserved memory.
+ * This is NIL_RTR0PROCESS if it's kernel memory. */
+ RTR0PROCESS R0Process;
+ } ResVirt;
+
+ /** RTR0MEMOBJTYPE_MAPPING */
+ struct
+ {
+ /** The process that owns the reserved memory.
+ * This is NIL_RTR0PROCESS if it's kernel memory. */
+ RTR0PROCESS R0Process;
+ } Mapping;
+ } u;
+
+} RTR0MEMOBJINTERNAL;
+
+
+/**
+ * Checks if this is mapping or not.
+ *
+ * @returns true if it's a mapping, otherwise false.
+ * @param pMem The ring-0 memory object handle.
+ * @see RTR0MemObjIsMapping
+ */
+DECLINLINE(bool) rtR0MemObjIsMapping(PRTR0MEMOBJINTERNAL pMem)
+{
+ switch (pMem->enmType)
+ {
+ case RTR0MEMOBJTYPE_MAPPING:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+
+/**
+ * Checks page level protection can be changed on this object.
+ *
+ * @returns true / false.
+ * @param pMem The ring-0 memory object handle.
+ */
+DECLINLINE(bool) rtR0MemObjIsProtectable(PRTR0MEMOBJINTERNAL pMem)
+{
+ switch (pMem->enmType)
+ {
+ case RTR0MEMOBJTYPE_MAPPING:
+ case RTR0MEMOBJTYPE_PAGE:
+ case RTR0MEMOBJTYPE_LOW:
+ case RTR0MEMOBJTYPE_CONT:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+
+/**
+ * Checks if RTR0MEMOBJ::pv is a ring-3 pointer or not.
+ *
+ * @returns true if it's a object with a ring-3 address, otherwise false.
+ * @param pMem The ring-0 memory object handle.
+ */
+DECLINLINE(bool) rtR0MemObjIsRing3(PRTR0MEMOBJINTERNAL pMem)
+{
+ switch (pMem->enmType)
+ {
+ case RTR0MEMOBJTYPE_RES_VIRT:
+ return pMem->u.ResVirt.R0Process != NIL_RTR0PROCESS;
+ case RTR0MEMOBJTYPE_LOCK:
+ return pMem->u.Lock.R0Process != NIL_RTR0PROCESS;
+ case RTR0MEMOBJTYPE_MAPPING:
+ return pMem->u.Mapping.R0Process != NIL_RTR0PROCESS;
+ default:
+ return false;
+ }
+}
+
+
+/**
+ * Frees the memory object (but not the handle).
+ * Any OS specific handle resources will be freed by this call.
+ *
+ * @returns IPRT status code. On failure it is assumed that the object remains valid.
+ * @param pMem The ring-0 memory object handle to the memory which should be freed.
+ */
+DECLHIDDEN(int) rtR0MemObjNativeFree(PRTR0MEMOBJINTERNAL pMem);
+
+/**
+ * Allocates page aligned virtual kernel memory.
+ *
+ * The memory is taken from a non paged (= fixed physical memory backing) pool.
+ *
+ * @returns IPRT status code.
+ * @param ppMem Where to store the ring-0 memory object handle.
+ * @param cb Number of bytes to allocate, page aligned.
+ * @param fExecutable Flag indicating whether it should be permitted to executed code in the memory object.
+ */
+DECLHIDDEN(int) rtR0MemObjNativeAllocPage(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable);
+
+/**
+ * Allocates page aligned virtual kernel memory with physical backing below 4GB.
+ *
+ * The physical memory backing the allocation is fixed.
+ *
+ * @returns IPRT status code.
+ * @param ppMem Where to store the ring-0 memory object handle.
+ * @param cb Number of bytes to allocate, page aligned.
+ * @param fExecutable Flag indicating whether it should be permitted to executed code in the memory object.
+ */
+DECLHIDDEN(int) rtR0MemObjNativeAllocLow(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable);
+
+/**
+ * Allocates page aligned virtual kernel memory with contiguous physical backing below 4GB.
+ *
+ * The physical memory backing the allocation is fixed.
+ *
+ * @returns IPRT status code.
+ * @param ppMem Where to store the ring-0 memory object handle.
+ * @param cb Number of bytes to allocate, page aligned.
+ * @param fExecutable Flag indicating whether it should be permitted to executed code in the memory object.
+ */
+DECLHIDDEN(int) rtR0MemObjNativeAllocCont(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable);
+
+/**
+ * Locks a range of user virtual memory.
+ *
+ * @returns IPRT status code.
+ * @param ppMem Where to store the ring-0 memory object handle.
+ * @param R3Ptr User virtual address, page aligned.
+ * @param cb Number of bytes to lock, page aligned.
+ * @param fAccess The desired access, a combination of RTMEM_PROT_READ
+ * and RTMEM_PROT_WRITE.
+ * @param R0Process The process to lock pages in.
+ */
+DECLHIDDEN(int) rtR0MemObjNativeLockUser(PPRTR0MEMOBJINTERNAL ppMem, RTR3PTR R3Ptr, size_t cb, uint32_t fAccess, RTR0PROCESS R0Process);
+
+/**
+ * Locks a range of kernel virtual memory.
+ *
+ * @returns IPRT status code.
+ * @param ppMem Where to store the ring-0 memory object handle.
+ * @param pv Kernel virtual address, page aligned.
+ * @param cb Number of bytes to lock, page aligned.
+ * @param fAccess The desired access, a combination of RTMEM_PROT_READ
+ * and RTMEM_PROT_WRITE.
+ */
+DECLHIDDEN(int) rtR0MemObjNativeLockKernel(PPRTR0MEMOBJINTERNAL ppMem, void *pv, size_t cb, uint32_t fAccess);
+
+/**
+ * Allocates contiguous page aligned physical memory without (necessarily) any
+ * kernel mapping.
+ *
+ * @returns IPRT status code.
+ * @param ppMem Where to store the ring-0 memory object handle.
+ * @param cb Number of bytes to allocate, page aligned.
+ * @param PhysHighest The highest permitable address (inclusive).
+ * NIL_RTHCPHYS if any address is acceptable.
+ * @param uAlignment The alignment of the reserved memory.
+ * Supported values are PAGE_SIZE, _2M, _4M and _1G.
+ */
+DECLHIDDEN(int) rtR0MemObjNativeAllocPhys(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, RTHCPHYS PhysHighest, size_t uAlignment);
+
+/**
+ * Allocates non-contiguous page aligned physical memory without (necessarily) any kernel mapping.
+ *
+ * @returns IPRT status code.
+ * @retval VERR_NOT_SUPPORTED if it's not possible to allocated unmapped
+ * physical memory on this platform.
+ * @param ppMem Where to store the ring-0 memory object handle.
+ * @param cb Number of bytes to allocate, page aligned.
+ * @param PhysHighest The highest permitable address (inclusive).
+ * NIL_RTHCPHYS if any address is acceptable.
+ */
+DECLHIDDEN(int) rtR0MemObjNativeAllocPhysNC(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, RTHCPHYS PhysHighest);
+
+/**
+ * Creates a page aligned, contiguous, physical memory object.
+ *
+ * @returns IPRT status code.
+ * @param ppMem Where to store the ring-0 memory object handle.
+ * @param Phys The physical address to start at, page aligned.
+ * @param cb The size of the object in bytes, page aligned.
+ * @param uCachePolicy One of the RTMEM_CACHE_XXX modes.
+ */
+DECLHIDDEN(int) rtR0MemObjNativeEnterPhys(PPRTR0MEMOBJINTERNAL ppMem, RTHCPHYS Phys, size_t cb, uint32_t uCachePolicy);
+
+/**
+ * Reserves kernel virtual address space.
+ *
+ * @returns IPRT status code.
+ * Return VERR_NOT_SUPPORTED to indicate that the user should employ fallback strategies.
+ * @param ppMem Where to store the ring-0 memory object handle.
+ * @param pvFixed Requested address. (void *)-1 means any address. This matches uAlignment if specified.
+ * @param cb The number of bytes to reserve, page aligned.
+ * @param uAlignment The alignment of the reserved memory; PAGE_SIZE, _2M or _4M.
+ */
+DECLHIDDEN(int) rtR0MemObjNativeReserveKernel(PPRTR0MEMOBJINTERNAL ppMem, void *pvFixed, size_t cb, size_t uAlignment);
+
+/**
+ * Reserves user virtual address space in the current process.
+ *
+ * @returns IPRT status code.
+ * @param ppMem Where to store the ring-0 memory object handle.
+ * @param R3PtrFixed Requested address. (RTR3PTR)-1 means any address. This matches uAlignment if specified.
+ * @param cb The number of bytes to reserve, page aligned.
+ * @param uAlignment The alignment of the reserved memory; PAGE_SIZE, _2M or _4M.
+ * @param R0Process The process to reserve the memory in.
+ */
+DECLHIDDEN(int) rtR0MemObjNativeReserveUser(PPRTR0MEMOBJINTERNAL ppMem, RTR3PTR R3PtrFixed, size_t cb, size_t uAlignment, RTR0PROCESS R0Process);
+
+/**
+ * Maps a memory object into user virtual address space in the current process.
+ *
+ * @returns IPRT status code.
+ * @retval VERR_NOT_SUPPORTED see RTR0MemObjMapKernelEx.
+ *
+ * @param ppMem Where to store the ring-0 memory object handle of the mapping object.
+ * @param pMemToMap The object to be map.
+ * @param pvFixed Requested address. (void *)-1 means any address. This matches uAlignment if specified.
+ * @param uAlignment The alignment of the reserved memory; PAGE_SIZE, _2M or _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.
+ */
+DECLHIDDEN(int) rtR0MemObjNativeMapKernel(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ pMemToMap, void *pvFixed, size_t uAlignment,
+ unsigned fProt, size_t offSub, size_t cbSub);
+
+/**
+ * Maps a memory object into user virtual address space in the current process.
+ *
+ * @returns IPRT status code.
+ * @param ppMem Where to store the ring-0 memory object handle of the mapping object.
+ * @param pMemToMap The object to be map.
+ * @param R3PtrFixed Requested address. (RTR3PTR)-1 means any address. This matches uAlignment if specified.
+ * @param uAlignment The alignment of the reserved memory; PAGE_SIZE, _2M or _4M.
+ * @param fProt Combination of RTMEM_PROT_* flags (except RTMEM_PROT_NONE).
+ * @param R0Process The process to map the memory into.
+ */
+DECLHIDDEN(int) rtR0MemObjNativeMapUser(PPRTR0MEMOBJINTERNAL ppMem, PRTR0MEMOBJINTERNAL pMemToMap, RTR3PTR R3PtrFixed, size_t uAlignment, unsigned fProt, RTR0PROCESS R0Process);
+
+/**
+ * Change the page level protection of one or more pages in a memory object.
+ *
+ * @returns IPRT status code.
+ * @retval VERR_NOT_SUPPORTED see RTR0MemObjProtect.
+ *
+ * @param pMem The memory object.
+ * @param offSub Offset into the memory object. Page aligned.
+ * @param cbSub Number of bytes to change the protection of. Page
+ * aligned.
+ * @param fProt Combination of RTMEM_PROT_* flags.
+ */
+DECLHIDDEN(int) rtR0MemObjNativeProtect(PRTR0MEMOBJINTERNAL pMem, size_t offSub, size_t cbSub, uint32_t fProt);
+
+/**
+ * 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 pMem The ring-0 memory object handle.
+ * @param iPage The page number within the object (valid).
+ */
+DECLHIDDEN(RTHCPHYS) rtR0MemObjNativeGetPagePhysAddr(PRTR0MEMOBJINTERNAL pMem, size_t iPage);
+
+DECLHIDDEN(PRTR0MEMOBJINTERNAL) rtR0MemObjNew(size_t cbSelf, RTR0MEMOBJTYPE enmType, void *pv, size_t cb);
+DECLHIDDEN(void) rtR0MemObjDelete(PRTR0MEMOBJINTERNAL pMem);
+
+/** @} */
+
+RT_C_DECLS_END
+
+#endif
+
--- /dev/null
+/* $Id: process.h $ */
+/** @file
+ * IPRT - Internal RTProc header.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___internal_process_h
+#define ___internal_process_h
+
+#include <iprt/process.h>
+#include <iprt/param.h>
+
+RT_C_DECLS_BEGIN
+
+extern DECLHIDDEN(RTPROCESS) g_ProcessSelf;
+extern DECLHIDDEN(RTPROCPRIORITY) g_enmProcessPriority;
+extern DECLHIDDEN(char) g_szrtProcExePath[RTPATH_MAX];
+extern DECLHIDDEN(size_t) g_cchrtProcExePath;
+extern DECLHIDDEN(size_t) g_cchrtProcDir;
+extern DECLHIDDEN(size_t) g_offrtProcName;
+extern DECLHIDDEN(bool volatile) g_frtAtExitCalled;
+
+/**
+ * Validates and sets the process priority.
+ * This will check that all rtThreadNativeSetPriority() will success for all the
+ * thread types when applied to the current thread.
+ *
+ * @returns iprt status code.
+ * @param enmPriority The priority to validate and set.
+ * @remark Located in sched.
+ */
+DECLHIDDEN(int) rtProcNativeSetPriority(RTPROCPRIORITY enmPriority);
+
+/**
+ * Determines the full path to the executable image.
+ *
+ * This is called by rtR3Init.
+ *
+ * @returns IPRT status code.
+ *
+ * @param pszPath Pointer to the g_szrtProcExePath buffer.
+ * @param cchPath The size of the buffer.
+ */
+DECLHIDDEN(int) rtProcInitExePath(char *pszPath, size_t cchPath);
+
+RT_C_DECLS_END
+
+#endif
+
--- /dev/null
+/* $Id: sched.h $ */
+/** @file
+ * IPRT - Internal RTSched header.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___internal_sched_h
+#define ___internal_sched_h
+
+#include <iprt/thread.h>
+#include "internal/process.h"
+#include "internal/thread.h"
+
+RT_C_DECLS_BEGIN
+
+/**
+ * Calculate the scheduling properties for all the threads in the default
+ * process priority, assuming the current thread have the type enmType.
+ *
+ * @returns iprt status code.
+ * @param enmType The thread type to be assumed for the current thread.
+ */
+DECLHIDDEN(int) rtSchedNativeCalcDefaultPriority(RTTHREADTYPE enmType);
+
+RT_C_DECLS_END
+
+#endif
--- /dev/null
+/* $Id: string.h $ */
+/** @file
+ * IPRT - Internal RTStr header.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___internal_string_h
+#define ___internal_string_h
+
+#include <iprt/string.h>
+
+RT_C_DECLS_BEGIN
+
+/** @def RTSTR_STRICT
+ * Enables strict assertions on bad string encodings.
+ */
+#ifdef DOXYGEN_RUNNING
+# define RTSTR_STRICT
+#endif
+/*#define RTSTR_STRICT*/
+
+#ifdef RTSTR_STRICT
+# define RTStrAssertMsgFailed(msg) AssertMsgFailed(msg)
+# define RTStrAssertMsgReturn(expr, msg, rc) AssertMsgReturn(expr, msg, rc)
+#else
+# define RTStrAssertMsgFailed(msg) do { } while (0)
+# define RTStrAssertMsgReturn(expr, msg, rc) do { if (!(expr)) return rc; } while (0)
+#endif
+
+DECLHIDDEN(size_t) rtstrFormatRt(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, const char **ppszFormat, va_list *pArgs,
+ int cchWidth, int cchPrecision, unsigned fFlags, char chArgSize);
+DECLHIDDEN(size_t) rtstrFormatType(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, const char **ppszFormat, va_list *pArgs,
+ int cchWidth, int cchPrecision, unsigned fFlags, char chArgSize);
+
+/**
+ * Format kernel address into @a pszBuf.
+ *
+ * @returns Number of bytes returned.
+ * @param pszBuf The return buffer.
+ * @param cbBuf The buffer size.
+ * @param uPtr The ring-0 pointer value.
+ * @param cchWidth The specified width, -1 if not given.
+ * @param cchPrecision The specified precision.
+ * @param fFlags Format flags, RTSTR_F_XXX.
+ */
+DECLHIDDEN(size_t) rtStrFormatKernelAddress(char *pszBuf, size_t cbBuf, RTR0INTPTR uPtr, signed int cchWidth,
+ signed int cchPrecision, unsigned int fFlags);
+
+#ifdef RT_WITH_ICONV_CACHE
+DECLHIDDEN(void) rtStrIconvCacheInit(struct RTTHREADINT *pThread);
+DECLHIDDEN(void) rtStrIconvCacheDestroy(struct RTTHREADINT *pThread);
+#endif
+
+/**
+ * Indexes into RTTHREADINT::ahIconvs
+ */
+typedef enum RTSTRICONV
+{
+ /** UTF-8 to the locale codeset (LC_CTYPE). */
+ RTSTRICONV_UTF8_TO_LOCALE = 0,
+ /** The locale codeset (LC_CTYPE) to UTF-8. */
+ RTSTRICONV_LOCALE_TO_UTF8,
+ /** UTF-8 to the filesystem codeset - if different from the locale codeset. */
+ RTSTRICONV_UTF8_TO_FS,
+ /** The filesystem codeset to UTF-8. */
+ RTSTRICONV_FS_TO_UTF8,
+ /** The end of the valid indexes. */
+ RTSTRICONV_END
+} RTSTRICONV;
+
+DECLHIDDEN(int) rtStrConvert(const char *pchInput, size_t cchInput, const char *pszInputCS,
+ char **ppszOutput, size_t cbOutput, const char *pszOutputCS,
+ unsigned cFactor, RTSTRICONV enmCacheIdx);
+DECLHIDDEN(const char *) rtStrGetLocaleCodeset(void);
+DECLHIDDEN(int) rtUtf8Length(const char *psz, size_t cch, size_t *pcuc, size_t *pcchActual);
+
+DECLHIDDEN(int) rtStrToIpAddr6Str(const char *psz, char *pszAddrOut, size_t addrOutSize, char *pszPortOut, size_t portOutSize, bool followRfc);
+
+RT_C_DECLS_END
+
+#endif
+
--- /dev/null
+/* $Id: thread.h $ */
+/** @file
+ * IPRT - Internal RTThread header.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___thread_h
+#define ___thread_h
+
+#include <iprt/types.h>
+#include <iprt/thread.h>
+#include <iprt/avl.h>
+#ifdef IN_RING3
+# include <iprt/process.h>
+# include <iprt/critsect.h>
+#endif
+#include "internal/lockvalidator.h"
+#include "internal/magics.h"
+#ifdef RT_WITH_ICONV_CACHE
+# include "internal/string.h"
+#endif
+
+RT_C_DECLS_BEGIN
+
+
+/** Max thread name length. */
+#define RTTHREAD_NAME_LEN 16
+#ifdef IPRT_WITH_GENERIC_TLS
+/** The number of TLS entries for the generic implementation. */
+# define RTTHREAD_TLS_ENTRIES 64
+#endif
+
+/**
+ * Internal representation of a thread.
+ */
+typedef struct RTTHREADINT
+{
+ /** Avl node core - the key is the native thread id. */
+ AVLPVNODECORE Core;
+ /** Magic value (RTTHREADINT_MAGIC). */
+ uint32_t u32Magic;
+ /** Reference counter. */
+ uint32_t volatile cRefs;
+ /** The current thread state. */
+ RTTHREADSTATE volatile enmState;
+ /** Set when really sleeping. */
+ bool volatile fReallySleeping;
+#if defined(RT_OS_WINDOWS) && defined(IN_RING3)
+ /** The thread handle
+ * This is not valid until the create function has returned! */
+ uintptr_t hThread;
+#endif
+#if defined(RT_OS_LINUX) && defined(IN_RING3)
+ /** The thread ID.
+ * This is not valid before rtThreadMain has been called by the new thread. */
+ pid_t tid;
+#endif
+#if defined(RT_OS_SOLARIS) && defined(IN_RING0)
+ /** Debug thread ID needed for thread_join. */
+ uint64_t tid;
+#endif
+ /** The user event semaphore. */
+ RTSEMEVENTMULTI EventUser;
+ /** The terminated event semaphore. */
+ RTSEMEVENTMULTI EventTerminated;
+ /** The thread type. */
+ RTTHREADTYPE enmType;
+ /** The thread creation flags. (RTTHREADFLAGS) */
+ unsigned fFlags;
+ /** Internal flags. (RTTHREADINT_FLAGS_ *) */
+ uint32_t fIntFlags;
+ /** The result code. */
+ int rc;
+ /** Thread function. */
+ PFNRTTHREAD pfnThread;
+ /** Thread function argument. */
+ void *pvUser;
+ /** Actual stack size. */
+ size_t cbStack;
+#ifdef IN_RING3
+ /** The lock validator data. */
+ RTLOCKVALPERTHREAD LockValidator;
+#endif /* IN_RING3 */
+#ifdef RT_WITH_ICONV_CACHE
+ /** Handle cache for iconv.
+ * @remarks ASSUMES sizeof(void *) >= sizeof(iconv_t). */
+ void *ahIconvs[RTSTRICONV_END];
+#endif
+#ifdef IPRT_WITH_GENERIC_TLS
+ /** The TLS entries for this thread. */
+ void *apvTlsEntries[RTTHREAD_TLS_ENTRIES];
+#endif
+ /** Thread name. */
+ char szName[RTTHREAD_NAME_LEN];
+} RTTHREADINT;
+/** Pointer to the internal representation of a thread. */
+typedef RTTHREADINT *PRTTHREADINT;
+
+
+/** @name RTTHREADINT::fIntFlags Masks and Bits.
+ * @{ */
+/** Set if the thread is an alien thread.
+ * Clear if the thread was created by IPRT. */
+#define RTTHREADINT_FLAGS_ALIEN RT_BIT(0)
+/** Set if the thread has terminated.
+ * Clear if the thread is running. */
+#define RTTHREADINT_FLAGS_TERMINATED RT_BIT(1)
+/** This bit is set if the thread is in the AVL tree. */
+#define RTTHREADINT_FLAG_IN_TREE_BIT 2
+/** @copydoc RTTHREADINT_FLAG_IN_TREE_BIT */
+#define RTTHREADINT_FLAG_IN_TREE RT_BIT(RTTHREADINT_FLAG_IN_TREE_BIT)
+/** Set if it's the main thread. */
+#define RTTHREADINT_FLAGS_MAIN RT_BIT(3)
+/** @} */
+
+
+/**
+ * Initialize the native part of the thread management.
+ *
+ * Generally a TLS entry will be allocated at this point (Ring-3).
+ *
+ * @returns iprt status code.
+ */
+DECLHIDDEN(int) rtThreadNativeInit(void);
+
+#ifdef IN_RING3
+/**
+ * Called when IPRT was first initialized in unobtrusive mode and later changed
+ * to obtrustive.
+ *
+ * This is only applicable in ring-3.
+ */
+DECLHIDDEN(void) rtThreadNativeReInitObtrusive(void);
+#endif
+
+/**
+ * Create a native thread.
+ * This creates the thread as described in pThreadInt and stores the thread id in *pThread.
+ *
+ * @returns iprt status code.
+ * @param pThreadInt The thread data structure for the thread.
+ * @param pNativeThread Where to store the native thread identifier.
+ */
+DECLHIDDEN(int) rtThreadNativeCreate(PRTTHREADINT pThreadInt, PRTNATIVETHREAD pNativeThread);
+
+/**
+ * Adopts a thread, this is called immediately after allocating the
+ * thread structure.
+ *
+ * @param pThread Pointer to the thread structure.
+ */
+DECLHIDDEN(int) rtThreadNativeAdopt(PRTTHREADINT pThread);
+
+/**
+ * Called from rtThreadDestroy so that the TLS entry and any native data in the
+ * thread structure can be cleared.
+ *
+ * @param pThread The thread structure.
+ */
+DECLHIDDEN(void) rtThreadNativeDestroy(PRTTHREADINT pThread);
+
+#ifdef IN_RING0
+/**
+ * Called from rtThreadWait when the last thread has completed in order to make
+ * sure it's all the way out of IPRT before RTR0Term is called.
+ *
+ * @param pThread The thread structure.
+ */
+DECLHIDDEN(void) rtThreadNativeWaitKludge(PRTTHREADINT pThread);
+#endif
+
+
+/**
+ * Sets the priority of the thread according to the thread type
+ * and current process priority.
+ *
+ * The RTTHREADINT::enmType member has not yet been updated and will be updated by
+ * the caller on a successful return.
+ *
+ * @returns iprt status code.
+ * @param pThread The thread in question.
+ * @param enmType The thread type.
+ * @remark Located in sched.
+ */
+DECLHIDDEN(int) rtThreadNativeSetPriority(PRTTHREADINT pThread, RTTHREADTYPE enmType);
+
+#ifdef IN_RING3
+# ifdef RT_OS_WINDOWS
+/**
+ * Callback for when a native thread is detaching.
+ *
+ * It give the Win32/64 backend a chance to terminate alien
+ * threads properly.
+ */
+DECLHIDDEN(void) rtThreadNativeDetach(void);
+
+/**
+ * Internal function for informing the debugger about a thread.
+ * @param pThread The thread. May differ from the calling thread.
+ */
+DECLHIDDEN(void) rtThreadNativeInformDebugger(PRTTHREADINT pThread);
+# endif
+#endif /* IN_RING3 */
+
+
+/* thread.cpp */
+DECLCALLBACK(DECLHIDDEN(int)) rtThreadMain(PRTTHREADINT pThread, RTNATIVETHREAD NativeThread, const char *pszThreadName);
+DECLHIDDEN(uint32_t) rtThreadRelease(PRTTHREADINT pThread);
+DECLHIDDEN(void) rtThreadTerminate(PRTTHREADINT pThread, int rc);
+DECLHIDDEN(PRTTHREADINT) rtThreadGetByNative(RTNATIVETHREAD NativeThread);
+DECLHIDDEN(PRTTHREADINT) rtThreadGet(RTTHREAD Thread);
+DECLHIDDEN(int) rtThreadInit(void);
+#ifdef IN_RING3
+DECLHIDDEN(void) rtThreadReInitObtrusive(void);
+#endif
+DECLHIDDEN(void) rtThreadTerm(void);
+DECLHIDDEN(void) rtThreadInsert(PRTTHREADINT pThread, RTNATIVETHREAD NativeThread);
+#ifdef IN_RING3
+DECLHIDDEN(int) rtThreadDoSetProcPriority(RTPROCPRIORITY enmPriority);
+#endif /* !IN_RING0 */
+#ifdef IPRT_WITH_GENERIC_TLS
+DECLHIDDEN(void) rtThreadClearTlsEntry(RTTLS iTls);
+DECLHIDDEN(void) rtThreadTlsDestruction(PRTTHREADINT pThread); /* in tls-generic.cpp */
+#endif
+
+#ifdef ___iprt_asm_h
+
+/**
+ * Gets the thread state.
+ *
+ * @returns The thread state.
+ * @param pThread The thread.
+ */
+DECLINLINE(RTTHREADSTATE) rtThreadGetState(PRTTHREADINT pThread)
+{
+ return pThread->enmState;
+}
+
+/**
+ * Sets the thread state.
+ *
+ * @param pThread The thread.
+ * @param enmNewState The new thread state.
+ */
+DECLINLINE(void) rtThreadSetState(PRTTHREADINT pThread, RTTHREADSTATE enmNewState)
+{
+ AssertCompile(sizeof(pThread->enmState) == sizeof(uint32_t));
+ ASMAtomicWriteU32((uint32_t volatile *)&pThread->enmState, enmNewState);
+}
+
+#endif
+
+RT_C_DECLS_END
+
+#endif
--- /dev/null
+/* $Id: time.h $ */
+/** @file
+ * IPRT - Internal RTTime header
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___internal_time_h
+#define ___internal_time_h
+
+#include <iprt/types.h>
+
+RT_C_DECLS_BEGIN
+
+#if defined(IN_RING3) || defined(IN_RC)
+
+extern DECLHIDDEN(uint64_t) g_u64ProgramStartNanoTS;
+extern DECLHIDDEN(uint64_t) g_u64ProgramStartMicroTS;
+extern DECLHIDDEN(uint64_t) g_u64ProgramStartMilliTS;
+
+#endif
+
+RT_C_DECLS_END
+
+#endif
--- /dev/null
+/** @file
+ * IPRT - Memory Allocation.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_alloc_h
+#define ___iprt_alloc_h
+
+/* Forwarding to the canonical header. */
+#include <iprt/mem.h>
+
+#endif
+
--- /dev/null
+/** @file
+ * IPRT - alloca().
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_alloca_h
+#define ___iprt_alloca_h
+
+#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)
+
+#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
+#endif
+
+#endif
+
--- /dev/null
+/** @file
+ * IPRT - AMD64 and x86 Specific Assembly Functions.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_asm_amd64_x86_h
+#define ___iprt_asm_amd64_x86_h
+
+#include <iprt/types.h>
+#include <iprt/assert.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
+# pragma warning(push)
+# pragma warning(disable:4668) /* Several incorrect __cplusplus uses. */
+# pragma warning(disable:4255) /* Incorrect __slwpcb prototype. */
+# include <intrin.h>
+# pragma warning(pop)
+ /* Emit the intrinsics at all optimization levels. */
+# pragma intrinsic(_ReadWriteBarrier)
+# pragma intrinsic(__cpuid)
+# 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 >= 14
+# pragma intrinsic(__halt)
+# endif
+# if RT_INLINE_ASM_USES_INTRIN >= 15
+# pragma intrinsic(__readeflags)
+# pragma intrinsic(__writeeflags)
+# pragma intrinsic(__rdtscp)
+# endif
+#endif
+
+
+/*
+ * Include #pragma aux definitions for Watcom C/C++.
+ */
+#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, *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 *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, *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 *PRGDTRALIGNED;
+
+
+/**
+ * Gets the content of the IDTR CPU register.
+ * @param pIdtr Where to store the IDTR contents.
+ */
+#if RT_INLINE_ASM_EXTERNAL
+DECLASM(void) ASMGetIDTR(PRTIDTR pIdtr);
+#else
+DECLINLINE(void) ASMGetIDTR(PRTIDTR pIdtr)
+{
+# if 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
+DECLASM(uint16_t) ASMGetIdtrLimit(void);
+#else
+DECLINLINE(uint16_t) ASMGetIdtrLimit(void)
+{
+ RTIDTRALIGNED TmpIdtr;
+# if 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
+DECLASM(void) ASMSetIDTR(const RTIDTR *pIdtr);
+#else
+DECLINLINE(void) ASMSetIDTR(const RTIDTR *pIdtr)
+{
+# if 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
+DECLASM(void) ASMGetGDTR(PRTGDTR pGdtr);
+#else
+DECLINLINE(void) ASMGetGDTR(PRTGDTR pGdtr)
+{
+# if 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
+DECLASM(void) ASMSetGDTR(const RTGDTR *pGdtr);
+#else
+DECLINLINE(void) ASMSetGDTR(const RTGDTR *pGdtr)
+{
+# if 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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+
+
+/**
+ * Get the GS register.
+ * @returns GS.
+ */
+#if RT_INLINE_ASM_EXTERNAL
+DECLASM(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
+
+
+/**
+ * Get the SS register.
+ * @returns SS.
+ */
+#if RT_INLINE_ASM_EXTERNAL
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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 >= 15
+ 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
+DECLASM(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 >= 15
+ __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
+DECLASM(RTCCUINTREG) ASMChangeFlags(RTCCUINTREG fAndEfl, RTCCUINTREG fOrEfl);
+#else
+DECLINLINE(RTCCUINTREG) ASMChangeFlags(RTCCUINTREG fAndEfl, RTCCUINTREG fOrEfl)
+{
+ RTCCUINTREG fOldEfl;
+# if RT_INLINE_ASM_GNU_STYLE
+# ifdef RT_ARCH_AMD64
+ __asm__ __volatile__("pushfq\n\t"
+ "movq (%%rsp), %0\n\t"
+ "andq %0, %1\n\t"
+ "orq %3, %1\n\t"
+ "mov %1, (%%rsp)\n\t"
+ "popfq\n\t"
+ : "=&r" (fOldEfl),
+ "=r" (fAndEfl)
+ : "1" (fAndEfl),
+ "rn" (fOrEfl) );
+# else
+ __asm__ __volatile__("pushfl\n\t"
+ "movl (%%esp), %0\n\t"
+ "andl %1, (%%esp)\n\t"
+ "orl %2, (%%esp)\n\t"
+ "popfl\n\t"
+ : "=&r" (fOldEfl)
+ : "rn" (fAndEfl),
+ "rn" (fOrEfl) );
+# endif
+# elif RT_INLINE_ASM_USES_INTRIN >= 15
+ fOldEfl = __readeflags();
+ __writeeflags((fOldEfl & fAndEfl) | fOrEfl);
+# else
+ __asm
+ {
+# ifdef RT_ARCH_AMD64
+ mov rdx, [fAndEfl]
+ mov rcx, [fOrEfl]
+ pushfq
+ mov rax, [rsp]
+ and rdx, rax
+ or rdx, rcx
+ mov [rsp], rdx
+ popfq
+ mov [fOldEfl], rax
+# else
+ mov edx, [fAndEfl]
+ mov ecx, [fOrEfl]
+ pushfd
+ mov eax, [esp]
+ and edx, eax
+ or edx, ecx
+ mov [esp], edx
+ popfd
+ mov [fOldEfl], eax
+# endif
+ }
+# endif
+ return fOldEfl;
+}
+#endif
+
+
+/**
+ * Modifies the [RE]FLAGS register by ORing in one or more flags.
+ * @returns Original value.
+ * @param fOrEfl The flags to be set (ORed in).
+ */
+#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < 15
+DECLASM(RTCCUINTREG) ASMAddFlags(RTCCUINTREG fOrEfl);
+#else
+DECLINLINE(RTCCUINTREG) ASMAddFlags(RTCCUINTREG fOrEfl)
+{
+ RTCCUINTREG fOldEfl;
+# if RT_INLINE_ASM_GNU_STYLE
+# ifdef RT_ARCH_AMD64
+ __asm__ __volatile__("pushfq\n\t"
+ "movq (%%rsp), %0\n\t"
+ "orq %1, (%%rsp)\n\t"
+ "popfq\n\t"
+ : "=&r" (fOldEfl)
+ : "rn" (fOrEfl) );
+# else
+ __asm__ __volatile__("pushfl\n\t"
+ "movl (%%esp), %0\n\t"
+ "orl %1, (%%esp)\n\t"
+ "popfl\n\t"
+ : "=&r" (fOldEfl)
+ : "rn" (fOrEfl) );
+# endif
+# elif RT_INLINE_ASM_USES_INTRIN >= 15
+ fOldEfl = __readeflags();
+ __writeeflags(fOldEfl | fOrEfl);
+# else
+ __asm
+ {
+# ifdef RT_ARCH_AMD64
+ mov rcx, [fOrEfl]
+ pushfq
+ mov rdx, [rsp]
+ or [rsp], rcx
+ popfq
+ mov [fOldEfl], rax
+# else
+ mov ecx, [fOrEfl]
+ pushfd
+ mov edx, [esp]
+ or [esp], ecx
+ popfd
+ mov [fOldEfl], eax
+# endif
+ }
+# endif
+ return fOldEfl;
+}
+#endif
+
+
+/**
+ * Modifies the [RE]FLAGS register by AND'ing out one or more flags.
+ * @returns Original value.
+ * @param fAndEfl The flags to keep.
+ */
+#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < 15
+DECLASM(RTCCUINTREG) ASMClearFlags(RTCCUINTREG fAndEfl);
+#else
+DECLINLINE(RTCCUINTREG) ASMClearFlags(RTCCUINTREG fAndEfl)
+{
+ RTCCUINTREG fOldEfl;
+# if RT_INLINE_ASM_GNU_STYLE
+# ifdef RT_ARCH_AMD64
+ __asm__ __volatile__("pushfq\n\t"
+ "movq (%%rsp), %0\n\t"
+ "andq %1, (%%rsp)\n\t"
+ "popfq\n\t"
+ : "=&r" (fOldEfl)
+ : "rn" (fAndEfl) );
+# else
+ __asm__ __volatile__("pushfl\n\t"
+ "movl (%%esp), %0\n\t"
+ "andl %1, (%%esp)\n\t"
+ "popfl\n\t"
+ : "=&r" (fOldEfl)
+ : "rn" (fAndEfl) );
+# endif
+# elif RT_INLINE_ASM_USES_INTRIN >= 15
+ fOldEfl = __readeflags();
+ __writeeflags(fOldEfl & fAndEfl);
+# else
+ __asm
+ {
+# ifdef RT_ARCH_AMD64
+ mov rdx, [fAndEfl]
+ pushfq
+ mov rdx, [rsp]
+ and [rsp], rdx
+ popfq
+ mov [fOldEfl], rax
+# else
+ mov edx, [fAndEfl]
+ pushfd
+ mov edx, [esp]
+ and [esp], edx
+ popfd
+ mov [fOldEfl], eax
+# endif
+ }
+# endif
+ return fOldEfl;
+}
+#endif
+
+
+/**
+ * Gets the content of the CPU timestamp counter register.
+ *
+ * @returns TSC.
+ */
+#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(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 < 15
+DECLASM(uint64_t) ASMReadTscWithAux(uint32_t *puAux);
+#else
+DECLINLINE(uint64_t) ASMReadTscWithAux(uint32_t *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 >= 15
+ 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 *pvEAX, void *pvEBX, void *pvECX, void *pvEDX);
+#else
+DECLINLINE(void) ASMCpuId(uint32_t uOperator, void *pvEAX, void *pvEBX, void *pvECX, void *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 *)pvEAX = (uint32_t)uRAX;
+ *(uint32_t *)pvEBX = (uint32_t)uRBX;
+ *(uint32_t *)pvECX = (uint32_t)uRCX;
+ *(uint32_t *)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 *)pvEAX = aInfo[0];
+ *(uint32_t *)pvEBX = aInfo[1];
+ *(uint32_t *)pvECX = aInfo[2];
+ *(uint32_t *)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 *)pvEAX = uEAX;
+ *(uint32_t *)pvEBX = uEBX;
+ *(uint32_t *)pvECX = uECX;
+ *(uint32_t *)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 *pvEAX, void *pvEBX, void *pvECX, void *pvEDX);
+#else
+DECLINLINE(void) ASMCpuId_Idx_ECX(uint32_t uOperator, uint32_t uIdxECX, void *pvEAX, void *pvEBX, void *pvECX, void *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 *)pvEAX = (uint32_t)uRAX;
+ *(uint32_t *)pvEBX = (uint32_t)uRBX;
+ *(uint32_t *)pvECX = (uint32_t)uRCX;
+ *(uint32_t *)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 *)pvEAX = aInfo[0];
+ *(uint32_t *)pvEBX = aInfo[1];
+ *(uint32_t *)pvECX = aInfo[2];
+ *(uint32_t *)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 *)pvEAX = uEAX;
+ *(uint32_t *)pvEBX = uEBX;
+ *(uint32_t *)pvECX = uECX;
+ *(uint32_t *)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 *pvEAX, void *pvEBX, void *pvECX, void *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
+DECLASM(void) ASMCpuId_ECX_EDX(uint32_t uOperator, void *pvECX, void *pvEDX);
+#else
+DECLINLINE(void) ASMCpuId_ECX_EDX(uint32_t uOperator, void *pvECX, void *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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+
+
+/**
+ * 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) ASMIsIntelCpuEx(uint32_t uEBX, uint32_t uECX, uint32_t uEDX)
+{
+ return uEBX == UINT32_C(0x756e6547)
+ && uECX == UINT32_C(0x6c65746e)
+ && uEDX == UINT32_C(0x49656e69);
+}
+
+
+/**
+ * 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 ASMIsIntelCpuEx(uEBX, uECX, uEDX);
+}
+
+
+/**
+ * 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) ASMIsAmdCpuEx(uint32_t uEBX, uint32_t uECX, uint32_t uEDX)
+{
+ return uEBX == UINT32_C(0x68747541)
+ && uECX == UINT32_C(0x444d4163)
+ && uEDX == UINT32_C(0x69746e65);
+}
+
+
+/**
+ * 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 ASMIsAmdCpuEx(uEBX, uECX, uEDX);
+}
+
+
+/**
+ * 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) ASMIsViaCentaurCpuEx(uint32_t uEBX, uint32_t uECX, uint32_t uEDX)
+{
+ return uEBX == UINT32_C(0x746e6543)
+ && uECX == UINT32_C(0x736c7561)
+ && uEDX == UINT32_C(0x48727561);
+}
+
+
+/**
+ * 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 ASMIsViaCentaurCpuEx(uEBX, uECX, uEDX);
+}
+
+
+/**
+ * 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) ASMIsValidStdRange(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) ASMIsValidExtRange(uint32_t uEAX)
+{
+ return uEAX >= UINT32_C(0x80000001) && uEAX <= UINT32_C(0x800fffff);
+}
+
+
+/**
+ * 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) ASMGetCpuFamily(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) ASMGetCpuModelIntel(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) ASMGetCpuModelAMD(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 ASMIsIntelCpuEx() or ASMIsIntelCpu().
+ */
+DECLINLINE(uint32_t) ASMGetCpuModel(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) ASMGetCpuStepping(uint32_t uEAX)
+{
+ return uEAX & 0xf;
+}
+
+
+/**
+ * Get cr0.
+ * @returns cr0.
+ */
+#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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 *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 *pXStateArea, uint64_t fComponents);
+
+
+struct X86FXSTATE;
+/**
+ * Save FPU and SSE CPU state.
+ * @param pXStateArea Where to save the state.
+ */
+DECLASM(void) ASMFxSave(struct X86FXSTATE *pXStateArea);
+
+/**
+ * Load FPU and SSE CPU state.
+ * @param pXStateArea Where to load the state from.
+ */
+DECLASM(void) ASMFxRstor(struct X86FXSTATE const *pXStateArea);
+
+
+/**
+ * Enables interrupts (EFLAGS.IF).
+ */
+#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(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
+DECLASM(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
+DECLASM(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 < 14
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(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
+DECLASM(void) ASMOutStrU8(RTIOPORT Port, uint8_t const *pau8, size_t c);
+#else
+DECLINLINE(void) ASMOutStrU8(RTIOPORT Port, uint8_t const *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 *)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
+DECLASM(void) ASMInStrU8(RTIOPORT Port, uint8_t *pau8, size_t c);
+#else
+DECLINLINE(void) ASMInStrU8(RTIOPORT Port, uint8_t *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
+DECLASM(void) ASMOutStrU16(RTIOPORT Port, uint16_t const *pau16, size_t c);
+#else
+DECLINLINE(void) ASMOutStrU16(RTIOPORT Port, uint16_t const *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 *)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
+DECLASM(void) ASMInStrU16(RTIOPORT Port, uint16_t *pau16, size_t c);
+#else
+DECLINLINE(void) ASMInStrU16(RTIOPORT Port, uint16_t *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
+DECLASM(void) ASMOutStrU32(RTIOPORT Port, uint32_t const *pau32, size_t c);
+#else
+DECLINLINE(void) ASMOutStrU32(RTIOPORT Port, uint32_t const *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 *)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
+DECLASM(void) ASMInStrU32(RTIOPORT Port, uint32_t *pau32, size_t c);
+#else
+DECLINLINE(void) ASMInStrU32(RTIOPORT Port, uint32_t *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 *)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
+DECLASM(void) ASMInvalidatePage(RTCCUINTXREG uPtr);
+#else
+DECLINLINE(void) ASMInvalidatePage(RTCCUINTXREG uPtr)
+{
+# if RT_INLINE_ASM_USES_INTRIN
+ __invlpg((void *)uPtr);
+
+# elif RT_INLINE_ASM_GNU_STYLE
+ __asm__ __volatile__("invlpg %0\n\t"
+ : : "m" (*(uint8_t *)(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
+DECLASM(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
+DECLASM(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 */
+
+/** @} */
+#endif
+
--- /dev/null
+/** @file
+ * IPRT - Assembly Routines for Optimizing some Integers Math Operations.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_asm_math_h
+#define ___iprt_asm_math_h
+
+#include <iprt/types.h>
+
+#if defined(_MSC_VER) && RT_INLINE_ASM_USES_INTRIN
+# pragma warning(push)
+# pragma warning(disable:4668) /* Several incorrect __cplusplus uses. */
+# pragma warning(disable:4255) /* Incorrect __slwpcb prototype. */
+# include <intrin.h>
+# pragma warning(pop)
+ /* Emit the intrinsics at all optimization levels. */
+# 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
+
+
+#if ARCH_BITS == 64
+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
+}
+#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
+
--- /dev/null
+/** @file
+ * IPRT - Assembly Functions.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_asm_h
+#define ___iprt_asm_h
+
+#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
+# pragma warning(push)
+# pragma warning(disable:4668) /* Several incorrect __cplusplus uses. */
+# pragma warning(disable:4255) /* Incorrect __slwpcb prototype. */
+# include <intrin.h>
+# pragma warning(pop)
+ /* Emit the intrinsics at all optimization levels. */
+# 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(_InterlockedIncrement)
+# pragma intrinsic(_InterlockedDecrement)
+# pragma intrinsic(_InterlockedExchange)
+# pragma intrinsic(_InterlockedExchangeAdd)
+# pragma intrinsic(_InterlockedCompareExchange)
+# 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(_InterlockedExchange64)
+# pragma intrinsic(_InterlockedExchangeAdd64)
+# pragma intrinsic(_InterlockedAnd64)
+# pragma intrinsic(_InterlockedOr64)
+# pragma intrinsic(_InterlockedIncrement64)
+# pragma intrinsic(_InterlockedDecrement64)
+# endif
+#endif
+
+/*
+ * Include #pragma aux definitions for Watcom C/C++.
+ */
+#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).
+ *
+ * @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 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)
+{
+ __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 && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86))
+DECLASM(void) ASMNopPause(void);
+#else
+DECLINLINE(void) ASMNopPause(void)
+{
+# 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
+# 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
+DECLASM(uint8_t) ASMAtomicXchgU8(volatile uint8_t *pu8, uint8_t u8);
+#else
+DECLINLINE(uint8_t) ASMAtomicXchgU8(volatile uint8_t *pu8, uint8_t u8)
+{
+# 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;
+}
+#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 *pi8, int8_t i8)
+{
+ return (int8_t)ASMAtomicXchgU8((volatile uint8_t *)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 *pf, bool f)
+{
+#ifdef _MSC_VER
+ return !!ASMAtomicXchgU8((volatile uint8_t *)pf, (uint8_t)f);
+#else
+ return (bool)ASMAtomicXchgU8((volatile uint8_t *)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
+DECLASM(uint16_t) ASMAtomicXchgU16(volatile uint16_t *pu16, uint16_t u16);
+#else
+DECLINLINE(uint16_t) ASMAtomicXchgU16(volatile uint16_t *pu16, uint16_t u16)
+{
+# 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;
+}
+#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 *pi16, int16_t i16)
+{
+ return (int16_t)ASMAtomicXchgU16((volatile uint16_t *)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 && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(uint32_t) ASMAtomicXchgU32(volatile uint32_t *pu32, uint32_t u32);
+#else
+DECLINLINE(uint32_t) ASMAtomicXchgU32(volatile uint32_t *pu32, uint32_t u32)
+{
+# if RT_INLINE_ASM_GNU_STYLE
+ __asm__ __volatile__("xchgl %0, %1\n\t"
+ : "=m" (*pu32),
+ "=r" (u32)
+ : "1" (u32),
+ "m" (*pu32));
+
+# elif RT_INLINE_ASM_USES_INTRIN
+ u32 = _InterlockedExchange((long *)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;
+}
+#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 *pi32, int32_t i32)
+{
+ return (int32_t)ASMAtomicXchgU32((volatile uint32_t *)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 && !RT_INLINE_ASM_USES_INTRIN) \
+ || RT_INLINE_DONT_MIX_CMPXCHG8B_AND_PIC
+DECLASM(uint64_t) ASMAtomicXchgU64(volatile uint64_t *pu64, uint64_t u64);
+#else
+DECLINLINE(uint64_t) ASMAtomicXchgU64(volatile uint64_t *pu64, uint64_t u64)
+{
+# if defined(RT_ARCH_AMD64)
+# if RT_INLINE_ASM_USES_INTRIN
+ u64 = _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));
+# else
+ __asm
+ {
+ mov rdx, [pu64]
+ mov rax, [u64]
+ xchg [rdx], rax
+ mov [u64], rax
+ }
+# endif
+# else /* !RT_ARCH_AMD64 */
+# 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));
+# 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) ));
+# 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
+# endif /* !RT_ARCH_AMD64 */
+ return u64;
+}
+#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 *pi64, int64_t i64)
+{
+ return (int64_t)ASMAtomicXchgU64((volatile uint64_t *)pi64, (uint64_t)i64);
+}
+
+
+/**
+ * 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 *) ASMAtomicXchgPtr(void * volatile *ppv, const void *pv)
+{
+#if ARCH_BITS == 32 || (ARCH_BITS == 16 && RT_FAR_DATA)
+ return (void *)ASMAtomicXchgU32((volatile uint32_t *)(void *)ppv, (uint32_t)pv);
+#elif ARCH_BITS == 64
+ return (void *)ASMAtomicXchgU64((volatile uint64_t *)(void *)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__
+# 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 * volatile *)(ppv), (void *)(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 *ppvRC, RTRCPTR pvRC)
+{
+ return (RTRCPTR)ASMAtomicXchgU32((uint32_t volatile *)(void *)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 *ppvR0, RTR0PTR pvR0)
+{
+#if R0_ARCH_BITS == 32 || (ARCH_BITS == 16 && RT_FAR_DATA)
+ return (RTR0PTR)ASMAtomicXchgU32((volatile uint32_t *)(void *)ppvR0, (uint32_t)pvR0);
+#elif R0_ARCH_BITS == 64
+ return (RTR0PTR)ASMAtomicXchgU64((volatile uint64_t *)(void *)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 *ppvR3, RTR3PTR pvR3)
+{
+#if R3_ARCH_BITS == 32 || (ARCH_BITS == 16 && RT_FAR_DATA)
+ return (RTR3PTR)ASMAtomicXchgU32((volatile uint32_t *)(void *)ppvR3, (uint32_t)pvR3);
+#elif R3_ARCH_BITS == 64
+ return (RTR3PTR)ASMAtomicXchgU64((volatile uint64_t *)(void *)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 && RT_FAR_DATA)
+# define ASMAtomicXchgHandle(ph, hNew, phRes) \
+ do { \
+ AssertCompile(sizeof(*(ph)) == sizeof(uint32_t)); \
+ AssertCompile(sizeof(*(phRes)) == sizeof(uint32_t)); \
+ *(uint32_t *)(phRes) = ASMAtomicXchgU32((uint32_t volatile *)(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 *)(phRes) = ASMAtomicXchgU64((uint64_t volatile *)(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 *)(void *)(pu), (uint8_t)(uNew)); break; \
+ case 2: ASMAtomicXchgU16((volatile uint16_t *)(void *)(pu), (uint16_t)(uNew)); break; \
+ case 4: ASMAtomicXchgU32((volatile uint32_t *)(void *)(pu), (uint32_t)(uNew)); break; \
+ case 8: ASMAtomicXchgU64((volatile uint64_t *)(void *)(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 *)(puRes) = ASMAtomicXchgU8((volatile uint8_t *)(void *)(pu), (uint8_t)(uNew)); break; \
+ case 2: *(uint16_t *)(puRes) = ASMAtomicXchgU16((volatile uint16_t *)(void *)(pu), (uint16_t)(uNew)); break; \
+ case 4: *(uint32_t *)(puRes) = ASMAtomicXchgU32((volatile uint32_t *)(void *)(pu), (uint32_t)(uNew)); break; \
+ case 8: *(uint64_t *)(puRes) = ASMAtomicXchgU64((volatile uint64_t *)(void *)(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.
+ */
+#if RT_INLINE_ASM_EXTERNAL || !RT_INLINE_ASM_GNU_STYLE
+DECLASM(bool) ASMAtomicCmpXchgU8(volatile uint8_t *pu8, const uint8_t u8New, const uint8_t u8Old);
+#else
+DECLINLINE(bool) ASMAtomicCmpXchgU8(volatile uint8_t *pu8, const uint8_t u8New, uint8_t u8Old)
+{
+ 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));
+ return (bool)u8Ret;
+}
+#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.
+ */
+DECLINLINE(bool) ASMAtomicCmpXchgS8(volatile int8_t *pi8, const int8_t i8New, const int8_t i8Old)
+{
+ return ASMAtomicCmpXchgU8((volatile uint8_t *)pi8, (const uint8_t)i8New, (const 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.
+ */
+DECLINLINE(bool) ASMAtomicCmpXchgBool(volatile bool *pf, const bool fNew, const bool fOld)
+{
+ return ASMAtomicCmpXchgU8((volatile uint8_t *)pf, (const uint8_t)fNew, (const 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.
+ */
+#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(bool) ASMAtomicCmpXchgU32(volatile uint32_t *pu32, const uint32_t u32New, const uint32_t u32Old);
+#else
+DECLINLINE(bool) ASMAtomicCmpXchgU32(volatile uint32_t *pu32, const uint32_t u32New, uint32_t u32Old)
+{
+# 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));
+ return (bool)u8Ret;
+
+# elif RT_INLINE_ASM_USES_INTRIN
+ return (uint32_t)_InterlockedCompareExchange((long *)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
+}
+#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.
+ */
+DECLINLINE(bool) ASMAtomicCmpXchgS32(volatile int32_t *pi32, const int32_t i32New, const int32_t i32Old)
+{
+ return ASMAtomicCmpXchgU32((volatile uint32_t *)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.
+ */
+#if (RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN) \
+ || RT_INLINE_DONT_MIX_CMPXCHG8B_AND_PIC
+DECLASM(bool) ASMAtomicCmpXchgU64(volatile uint64_t *pu64, const uint64_t u64New, const uint64_t u64Old);
+#else
+DECLINLINE(bool) ASMAtomicCmpXchgU64(volatile uint64_t *pu64, uint64_t u64New, uint64_t u64Old)
+{
+# if RT_INLINE_ASM_USES_INTRIN
+ return (uint64_t)_InterlockedCompareExchange64((__int64 *)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));
+ 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
+# else /* !RT_ARCH_AMD64 */
+ 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));
+# 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) ));
+# 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
+# endif /* !RT_ARCH_AMD64 */
+}
+#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.
+ */
+DECLINLINE(bool) ASMAtomicCmpXchgS64(volatile int64_t *pi64, const int64_t i64, const int64_t i64Old)
+{
+ return ASMAtomicCmpXchgU64((volatile uint64_t *)pi64, (uint64_t)i64, (uint64_t)i64Old);
+}
+
+
+/**
+ * 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.
+ */
+DECLINLINE(bool) ASMAtomicCmpXchgPtrVoid(void * volatile *ppv, const void *pvNew, const void *pvOld)
+{
+#if ARCH_BITS == 32 || (ARCH_BITS == 16 && RT_FAR_DATA)
+ return ASMAtomicCmpXchgU32((volatile uint32_t *)(void *)ppv, (uint32_t)pvNew, (uint32_t)pvOld);
+#elif ARCH_BITS == 64
+ return ASMAtomicCmpXchgU64((volatile uint64_t *)(void *)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.
+ */
+#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 * volatile *)(ppv), (void *)(pvNew), (void *)(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.
+ */
+#if HC_ARCH_BITS == 32 || (ARCH_BITS == 16 && RT_FAR_DATA)
+# define ASMAtomicCmpXchgHandle(ph, hNew, hOld, fRc) \
+ do { \
+ AssertCompile(sizeof(*(ph)) == sizeof(uint32_t)); \
+ (fRc) = ASMAtomicCmpXchgU32((uint32_t volatile *)(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 *)(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.
+ */
+#define ASMAtomicCmpXchgSize(pu, uNew, uOld, fRc) \
+ do { \
+ switch (sizeof(*(pu))) { \
+ case 4: (fRc) = ASMAtomicCmpXchgU32((volatile uint32_t *)(void *)(pu), (uint32_t)(uNew), (uint32_t)(uOld)); \
+ break; \
+ case 8: (fRc) = ASMAtomicCmpXchgU64((volatile uint64_t *)(void *)(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 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 && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(bool) ASMAtomicCmpXchgExU32(volatile uint32_t *pu32, const uint32_t u32New, const uint32_t u32Old, uint32_t *pu32Old);
+#else
+DECLINLINE(bool) ASMAtomicCmpXchgExU32(volatile uint32_t *pu32, const uint32_t u32New, const uint32_t u32Old, uint32_t *pu32Old)
+{
+# 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));
+ return (bool)u8Ret;
+
+# elif RT_INLINE_ASM_USES_INTRIN
+ return (*pu32Old =_InterlockedCompareExchange((long *)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
+}
+#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 *pi32, const int32_t i32New, const int32_t i32Old, int32_t *pi32Old)
+{
+ return ASMAtomicCmpXchgExU32((volatile uint32_t *)pi32, (uint32_t)i32New, (uint32_t)i32Old, (uint32_t *)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 && !RT_INLINE_ASM_USES_INTRIN) \
+ || RT_INLINE_DONT_MIX_CMPXCHG8B_AND_PIC
+DECLASM(bool) ASMAtomicCmpXchgExU64(volatile uint64_t *pu64, const uint64_t u64New, const uint64_t u64Old, uint64_t *pu64Old);
+#else
+DECLINLINE(bool) ASMAtomicCmpXchgExU64(volatile uint64_t *pu64, const uint64_t u64New, const uint64_t u64Old, uint64_t *pu64Old)
+{
+# if RT_INLINE_ASM_USES_INTRIN
+ return (*pu64Old =_InterlockedCompareExchange64((__int64 *)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));
+ 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
+# else /* !RT_ARCH_AMD64 */
+# if RT_INLINE_ASM_GNU_STYLE
+ uint64_t u64Ret;
+# if defined(PIC) || defined(__PIC__)
+ /* NB: 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. */
+ __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)),
+ "m" (*pu64),
+ "0" (u64Old)
+ : "memory" );
+# 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));
+# 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
+# endif /* !RT_ARCH_AMD64 */
+}
+#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 *pi64, const int64_t i64, const int64_t i64Old, int64_t *pi64Old)
+{
+ return ASMAtomicCmpXchgExU64((volatile uint64_t *)pi64, (uint64_t)i64, (uint64_t)i64Old, (uint64_t *)pi64Old);
+}
+
+/** @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 && RT_FAR_DATA)
+# 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 *)(pu), (uint32_t)(uNew), (uint32_t)(uOld), (uint32_t *)(puOldVal)); \
+ } 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 *)(pu), (uint64_t)(uNew), (uint64_t)(uOld), (uint64_t *)(puOldVal)); \
+ } 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 *)(void *)(pu), (uint32_t)(uNew), (uint32_t)(uOld), (uint32_t *)(uOldVal)); \
+ break; \
+ case 8: (fRc) = ASMAtomicCmpXchgExU64((volatile uint64_t *)(void *)(pu), (uint64_t)(uNew), (uint64_t)(uOld), (uint64_t *)(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 * volatile *ppv, const void *pvNew, const void *pvOld, void **ppvOld)
+{
+#if ARCH_BITS == 32 || (ARCH_BITS == 16 && RT_FAR_DATA)
+ return ASMAtomicCmpXchgExU32((volatile uint32_t *)(void *)ppv, (uint32_t)pvNew, (uint32_t)pvOld, (uint32_t *)ppvOld);
+#elif ARCH_BITS == 64
+ return ASMAtomicCmpXchgExU64((volatile uint64_t *)(void *)ppv, (uint64_t)pvNew, (uint64_t)pvOld, (uint64_t *)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 * volatile *)(ppv), (void *)(pvNew), (void *)(pvOld), (void **)(ppvOld))
+#endif
+
+
+/**
+ * Virtualization unfriendly serializing instruction, always exits.
+ */
+#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(void) ASMSerializeInstructionCpuId(void);
+#else
+DECLINLINE(void) ASMSerializeInstructionCpuId(void)
+{
+# 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
+DECLASM(void) ASMSerializeInstructionIRet(void);
+#else
+DECLINLINE(void) ASMSerializeInstructionIRet(void)
+{
+# 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");
+# 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 < 15
+DECLASM(void) ASMSerializeInstructionRdTscp(void);
+#else
+DECLINLINE(void) ASMSerializeInstructionRdTscp(void)
+{
+# 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 >= 15
+ uint32_t uIgnore;
+ _ReadWriteBarrier();
+ (void)__rdtscp(&uIgnore);
+ (void)uIgnore;
+# else
+ __asm
+ {
+ rdtscp
+ }
+# endif
+# endif
+}
+#endif
+
+
+/**
+ * Serialize Instruction.
+ */
+#if (defined(RT_ARCH_X86) && ARCH_BITS == 16) || defined(IN_GUEST)
+# define ASMSerializeInstruction() ASMSerializeInstructionIRet()
+#else
+# define ASMSerializeInstruction() ASMSerializeInstructionCpuId()
+#endif
+
+
+/**
+ * Memory fence, waits for any pending writes and reads to complete.
+ */
+DECLINLINE(void) ASMMemoryFence(void)
+{
+ /** @todo use mfence? check if all cpus we care for support it. */
+#if 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.
+ */
+DECLINLINE(void) ASMWriteFence(void)
+{
+ /** @todo use sfence? check if all cpus we care for support it. */
+ ASMMemoryFence();
+}
+
+
+/**
+ * Read fence, waits for any pending reads to complete.
+ */
+DECLINLINE(void) ASMReadFence(void)
+{
+ /** @todo use lfence? check if all cpus we care for support it. */
+ ASMMemoryFence();
+}
+
+
+/**
+ * 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 *pu8)
+{
+ ASMMemoryFence();
+ return *pu8; /* byte reads are atomic on x86 */
+}
+
+
+/**
+ * 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 *pu8)
+{
+ return *pu8; /* byte reads are atomic on x86 */
+}
+
+
+/**
+ * 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 *pi8)
+{
+ ASMMemoryFence();
+ return *pi8; /* byte reads are atomic on x86 */
+}
+
+
+/**
+ * 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 *pi8)
+{
+ return *pi8; /* byte reads are atomic on x86 */
+}
+
+
+/**
+ * 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 *pu16)
+{
+ ASMMemoryFence();
+ Assert(!((uintptr_t)pu16 & 1));
+ return *pu16;
+}
+
+
+/**
+ * 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 *pu16)
+{
+ Assert(!((uintptr_t)pu16 & 1));
+ return *pu16;
+}
+
+
+/**
+ * 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 *pi16)
+{
+ ASMMemoryFence();
+ Assert(!((uintptr_t)pi16 & 1));
+ return *pi16;
+}
+
+
+/**
+ * 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 *pi16)
+{
+ Assert(!((uintptr_t)pi16 & 1));
+ return *pi16;
+}
+
+
+/**
+ * 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 *pu32)
+{
+ ASMMemoryFence();
+ Assert(!((uintptr_t)pu32 & 3));
+#if ARCH_BITS == 16
+ AssertFailed(); /** @todo 16-bit */
+#endif
+ return *pu32;
+}
+
+
+/**
+ * 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 *pu32)
+{
+ Assert(!((uintptr_t)pu32 & 3));
+#if ARCH_BITS == 16
+ AssertFailed(); /** @todo 16-bit */
+#endif
+ return *pu32;
+}
+
+
+/**
+ * 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 *pi32)
+{
+ ASMMemoryFence();
+ Assert(!((uintptr_t)pi32 & 3));
+#if ARCH_BITS == 16
+ AssertFailed(); /** @todo 16-bit */
+#endif
+ return *pi32;
+}
+
+
+/**
+ * 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 *pi32)
+{
+ Assert(!((uintptr_t)pi32 & 3));
+#if ARCH_BITS == 16
+ AssertFailed(); /** @todo 16-bit */
+#endif
+ return *pi32;
+}
+
+
+/**
+ * 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 && !defined(RT_ARCH_AMD64)) \
+ || RT_INLINE_DONT_MIX_CMPXCHG8B_AND_PIC
+DECLASM(uint64_t) ASMAtomicReadU64(volatile uint64_t *pu64);
+#else
+DECLINLINE(uint64_t) ASMAtomicReadU64(volatile uint64_t *pu64)
+{
+ 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;
+# else /* !RT_ARCH_AMD64 */
+# 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));
+# else /* !PIC */
+ __asm__ __volatile__("lock; cmpxchg8b %1\n\t"
+ : "=A" (u64),
+ "+m" (*pu64)
+ : "0" (0ULL),
+ "b" (0),
+ "c" (0));
+# 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
+# endif /* !RT_ARCH_AMD64 */
+ 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 && !RT_INLINE_ASM_USES_INTRIN) \
+ || RT_INLINE_DONT_MIX_CMPXCHG8B_AND_PIC)
+DECLASM(uint64_t) ASMAtomicUoReadU64(volatile uint64_t *pu64);
+#else
+DECLINLINE(uint64_t) ASMAtomicUoReadU64(volatile uint64_t *pu64)
+{
+ 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;
+# else /* !RT_ARCH_AMD64 */
+# 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));
+# else /* !PIC */
+ __asm__ __volatile__("lock; cmpxchg8b %1\n\t"
+ : "=A" (u64),
+ "+m" (*pu64)
+ : "0" (0ULL),
+ "b" (0),
+ "c" (0));
+# 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
+# endif /* !RT_ARCH_AMD64 */
+ 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 *pi64)
+{
+ return (int64_t)ASMAtomicReadU64((volatile uint64_t *)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 *pi64)
+{
+ return (int64_t)ASMAtomicUoReadU64((volatile uint64_t *)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 *pcb)
+{
+#if ARCH_BITS == 64
+ return ASMAtomicReadU64((uint64_t volatile *)pcb);
+#elif ARCH_BITS == 32
+ return ASMAtomicReadU32((uint32_t volatile *)pcb);
+#elif ARCH_BITS == 16
+ AssertCompileSize(size_t, 2);
+ return ASMAtomicReadU16((uint16_t volatile *)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 *pcb)
+{
+#if ARCH_BITS == 64 || (ARCH_BITS == 16 && RT_FAR_DATA)
+ return ASMAtomicUoReadU64((uint64_t volatile *)pcb);
+#elif ARCH_BITS == 32
+ return ASMAtomicUoReadU32((uint32_t volatile *)pcb);
+#elif ARCH_BITS == 16
+ AssertCompileSize(size_t, 2);
+ return ASMAtomicUoReadU16((uint16_t volatile *)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 *) ASMAtomicReadPtr(void * volatile *ppv)
+{
+#if ARCH_BITS == 32 || (ARCH_BITS == 16 && RT_FAR_DATA)
+ return (void *)ASMAtomicReadU32((volatile uint32_t *)(void *)ppv);
+#elif ARCH_BITS == 64
+ return (void *)ASMAtomicReadU64((volatile uint64_t *)(void *)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__
+# 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 * volatile *)(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 *) ASMAtomicUoReadPtr(void * volatile *ppv)
+{
+#if ARCH_BITS == 32 || (ARCH_BITS == 16 && RT_FAR_DATA)
+ return (void *)ASMAtomicUoReadU32((volatile uint32_t *)(void *)ppv);
+#elif ARCH_BITS == 64
+ return (void *)ASMAtomicUoReadU64((volatile uint64_t *)(void *)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__
+# 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 * volatile *)(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 *pf)
+{
+ 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 *pf)
+{
+ 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 && RT_FAR_DATA)
+# define ASMAtomicReadHandle(ph, phRes) \
+ do { \
+ AssertCompile(sizeof(*(ph)) == sizeof(uint32_t)); \
+ AssertCompile(sizeof(*(phRes)) == sizeof(uint32_t)); \
+ *(uint32_t *)(phRes) = ASMAtomicReadU32((uint32_t volatile *)(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 *)(phRes) = ASMAtomicReadU64((uint64_t volatile *)(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 && RT_FAR_DATA)
+# define ASMAtomicUoReadHandle(ph, phRes) \
+ do { \
+ AssertCompile(sizeof(*(ph)) == sizeof(uint32_t)); \
+ AssertCompile(sizeof(*(phRes)) == sizeof(uint32_t)); \
+ *(uint32_t *)(phRes) = ASMAtomicUoReadU32((uint32_t volatile *)(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 *)(phRes) = ASMAtomicUoReadU64((uint64_t volatile *)(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 *)(puRes) = ASMAtomicReadU8( (volatile uint8_t *)(void *)(pu)); break; \
+ case 2: *(uint16_t *)(puRes) = ASMAtomicReadU16((volatile uint16_t *)(void *)(pu)); break; \
+ case 4: *(uint32_t *)(puRes) = ASMAtomicReadU32((volatile uint32_t *)(void *)(pu)); break; \
+ case 8: *(uint64_t *)(puRes) = ASMAtomicReadU64((volatile uint64_t *)(void *)(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 *)(puRes) = ASMAtomicUoReadU8( (volatile uint8_t *)(void *)(pu)); break; \
+ case 2: *(uint16_t *)(puRes) = ASMAtomicUoReadU16((volatile uint16_t *)(void *)(pu)); break; \
+ case 4: *(uint32_t *)(puRes) = ASMAtomicUoReadU32((volatile uint32_t *)(void *)(pu)); break; \
+ case 8: *(uint64_t *)(puRes) = ASMAtomicUoReadU64((volatile uint64_t *)(void *)(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 *pu8, uint8_t u8)
+{
+ 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 *pu8, uint8_t u8)
+{
+ *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 *pi8, int8_t i8)
+{
+ 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 *pi8, int8_t i8)
+{
+ *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 *pu16, uint16_t u16)
+{
+ 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 *pu16, uint16_t u16)
+{
+ 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 *pi16, int16_t i16)
+{
+ 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 *pi16, int16_t i16)
+{
+ 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 *pu32, uint32_t u32)
+{
+ 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 *pu32, uint32_t u32)
+{
+ 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 *pi32, int32_t i32)
+{
+ 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 *pi32, int32_t i32)
+{
+ 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 *pu64, uint64_t u64)
+{
+ 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 *pu64, uint64_t u64)
+{
+ 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 *pi64, int64_t i64)
+{
+ 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 *pi64, int64_t i64)
+{
+ Assert(!((uintptr_t)pi64 & 7));
+#if ARCH_BITS == 64
+ *pi64 = i64;
+#else
+ ASMAtomicXchgS64(pi64, i64);
+#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 *pf, bool f)
+{
+ ASMAtomicWriteU8((uint8_t volatile *)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 *pf, bool f)
+{
+ *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 * volatile *ppv, const void *pv)
+{
+#if ARCH_BITS == 32 || (ARCH_BITS == 16 && RT_FAR_DATA)
+ ASMAtomicWriteU32((volatile uint32_t *)(void *)ppv, (uint32_t)pv);
+#elif ARCH_BITS == 64
+ ASMAtomicWriteU64((volatile uint64_t *)(void *)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 * 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) )); \
+ \
+ ASMAtomicWritePtrVoid((void * volatile *)(ppvTypeChecked), (void *)(pvTypeChecked)); \
+ } while (0)
+#else
+# define ASMAtomicWritePtr(ppv, pv) \
+ do \
+ { \
+ AssertCompile(sizeof(*ppv) == sizeof(void *)); \
+ AssertCompile(sizeof(pv) == sizeof(void *)); \
+ Assert(!( (uintptr_t)ppv & ((ARCH_BITS / 8) - 1) )); \
+ \
+ ASMAtomicWritePtrVoid((void * volatile *)(ppv), (void *)(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.
+ */
+#ifdef __GNUC__
+# define ASMAtomicWriteNullPtr(ppv) \
+ do \
+ { \
+ __typeof__(*(ppv)) * const ppvTypeChecked = (ppv); \
+ AssertCompile(sizeof(*ppv) == sizeof(void *)); \
+ Assert(!( (uintptr_t)ppv & ((ARCH_BITS / 8) - 1) )); \
+ ASMAtomicWritePtrVoid((void * volatile *)(ppvTypeChecked), NULL); \
+ } while (0)
+#else
+# define ASMAtomicWriteNullPtr(ppv) \
+ do \
+ { \
+ AssertCompile(sizeof(*ppv) == sizeof(void *)); \
+ Assert(!( (uintptr_t)ppv & ((ARCH_BITS / 8) - 1) )); \
+ ASMAtomicWritePtrVoid((void * volatile *)(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.
+ */
+#ifdef __GNUC__
+# 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 *)); \
+ AssertCompile(sizeof(pv) == sizeof(void *)); \
+ 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 *)); \
+ 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 && RT_FAR_DATA)
+# define ASMAtomicWriteHandle(ph, hNew) \
+ do { \
+ AssertCompile(sizeof(*(ph)) == sizeof(uint32_t)); \
+ ASMAtomicWriteU32((uint32_t volatile *)(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 *)(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 && RT_FAR_DATA)
+# define ASMAtomicUoWriteHandle(ph, hNew) \
+ do { \
+ AssertCompile(sizeof(*(ph)) == sizeof(uint32_t)); \
+ ASMAtomicUoWriteU32((uint32_t volatile *)(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 *)(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 *)(void *)(pu), (uint8_t )(uNew)); break; \
+ case 2: ASMAtomicWriteU16((volatile uint16_t *)(void *)(pu), (uint16_t)(uNew)); break; \
+ case 4: ASMAtomicWriteU32((volatile uint32_t *)(void *)(pu), (uint32_t)(uNew)); break; \
+ case 8: ASMAtomicWriteU64((volatile uint64_t *)(void *)(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 *)(void *)(pu), (uint8_t )(uNew)); break; \
+ case 2: ASMAtomicUoWriteU16((volatile uint16_t *)(void *)(pu), (uint16_t)(uNew)); break; \
+ case 4: ASMAtomicUoWriteU32((volatile uint32_t *)(void *)(pu), (uint32_t)(uNew)); break; \
+ case 8: ASMAtomicUoWriteU64((volatile uint64_t *)(void *)(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.
+ */
+DECLASM(uint16_t) ASMAtomicAddU16(uint16_t volatile *pu16, uint32_t u16);
+
+
+/**
+ * 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 && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(uint32_t) ASMAtomicAddU32(uint32_t volatile *pu32, uint32_t u32);
+#else
+DECLINLINE(uint32_t) ASMAtomicAddU32(uint32_t volatile *pu32, uint32_t u32)
+{
+# if RT_INLINE_ASM_USES_INTRIN
+ u32 = _InterlockedExchangeAdd((long *)pu32, u32);
+ return u32;
+
+# elif RT_INLINE_ASM_GNU_STYLE
+ __asm__ __volatile__("lock; xaddl %0, %1\n\t"
+ : "=r" (u32),
+ "=m" (*pu32)
+ : "0" (u32),
+ "m" (*pu32)
+ : "memory");
+ 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
+}
+#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 *pi32, int32_t i32)
+{
+ return (int32_t)ASMAtomicAddU32((uint32_t volatile *)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 && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(uint64_t) ASMAtomicAddU64(uint64_t volatile *pu64, uint64_t u64);
+#else
+DECLINLINE(uint64_t) ASMAtomicAddU64(uint64_t volatile *pu64, uint64_t u64)
+{
+# if RT_INLINE_ASM_USES_INTRIN && defined(RT_ARCH_AMD64)
+ u64 = _InterlockedExchangeAdd64((__int64 *)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");
+ return u64;
+# 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 *pi64, int64_t i64)
+{
+ return (int64_t)ASMAtomicAddU64((uint64_t volatile *)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 *pcb, size_t cb)
+{
+#if ARCH_BITS == 64
+ AssertCompileSize(size_t, 8);
+ return ASMAtomicAddU64((uint64_t volatile *)pcb, cb);
+#elif ARCH_BITS == 32
+ AssertCompileSize(size_t, 4);
+ return ASMAtomicAddU32((uint32_t volatile *)pcb, cb);
+#elif ARCH_BITS == 16
+ AssertCompileSize(size_t, 2);
+ return ASMAtomicAddU16((uint16_t volatile *)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 *)(void *)(pu), (uint32_t)(uNew)); break; \
+ case 8: *(uint64_t *)(puOld) = ASMAtomicAddU64((volatile uint64_t *)(void *)(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 *pu16, uint32_t u16)
+{
+ 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 *pi16, int16_t i16)
+{
+ return (int16_t)ASMAtomicAddU16((uint16_t volatile *)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 *pu32, uint32_t u32)
+{
+ 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 *pi32, int32_t i32)
+{
+ return (int32_t)ASMAtomicAddU32((uint32_t volatile *)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 *pu64, uint64_t u64)
+{
+ 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 *pi64, int64_t i64)
+{
+ return (int64_t)ASMAtomicAddU64((uint64_t volatile *)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 *pcb, size_t cb)
+{
+#if ARCH_BITS == 64
+ return ASMAtomicSubU64((uint64_t volatile *)pcb, cb);
+#elif ARCH_BITS == 32
+ return ASMAtomicSubU32((uint32_t volatile *)pcb, cb);
+#elif ARCH_BITS == 16
+ AssertCompileSize(size_t, 2);
+ return ASMAtomicSubU16((uint16_t volatile *)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 *)(puOld) = ASMAtomicSubU32((volatile uint32_t *)(void *)(pu), (uint32_t)(uNew)); break; \
+ case 8: *(uint64_t *)(puOld) = ASMAtomicSubU64((volatile uint64_t *)(void *)(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.
+ */
+DECLASM(uint16_t) ASMAtomicIncU16(uint16_t volatile *pu16);
+
+
+/**
+ * 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 && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(uint32_t) ASMAtomicIncU32(uint32_t volatile *pu32);
+#else
+DECLINLINE(uint32_t) ASMAtomicIncU32(uint32_t volatile *pu32)
+{
+ uint32_t u32;
+# if RT_INLINE_ASM_USES_INTRIN
+ u32 = _InterlockedIncrement((long *)pu32);
+ return u32;
+
+# elif RT_INLINE_ASM_GNU_STYLE
+ __asm__ __volatile__("lock; xaddl %0, %1\n\t"
+ : "=r" (u32),
+ "=m" (*pu32)
+ : "0" (1),
+ "m" (*pu32)
+ : "memory");
+ 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
+}
+#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 *pi32)
+{
+ return (int32_t)ASMAtomicIncU32((uint32_t volatile *)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 && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(uint64_t) ASMAtomicIncU64(uint64_t volatile *pu64);
+#else
+DECLINLINE(uint64_t) ASMAtomicIncU64(uint64_t volatile *pu64)
+{
+# if RT_INLINE_ASM_USES_INTRIN && defined(RT_ARCH_AMD64)
+ uint64_t u64;
+ u64 = _InterlockedIncrement64((__int64 *)pu64);
+ return u64;
+
+# 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");
+ return u64 + 1;
+# 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 *pi64)
+{
+ return (int64_t)ASMAtomicIncU64((uint64_t volatile *)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(int64_t) ASMAtomicIncZ(size_t volatile *pcb)
+{
+#if ARCH_BITS == 64
+ return ASMAtomicIncU64((uint64_t volatile *)pcb);
+#elif ARCH_BITS == 32
+ return ASMAtomicIncU32((uint32_t volatile *)pcb);
+#elif ARCH_BITS == 16
+ return ASMAtomicIncU16((uint16_t volatile *)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.
+ */
+DECLASM(uint32_t) ASMAtomicDecU16(uint16_t volatile *pu16);
+
+
+/**
+ * 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 && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(uint32_t) ASMAtomicDecU32(uint32_t volatile *pu32);
+#else
+DECLINLINE(uint32_t) ASMAtomicDecU32(uint32_t volatile *pu32)
+{
+ uint32_t u32;
+# if RT_INLINE_ASM_USES_INTRIN
+ u32 = _InterlockedDecrement((long *)pu32);
+ return u32;
+
+# elif RT_INLINE_ASM_GNU_STYLE
+ __asm__ __volatile__("lock; xaddl %0, %1\n\t"
+ : "=r" (u32),
+ "=m" (*pu32)
+ : "0" (-1),
+ "m" (*pu32)
+ : "memory");
+ 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
+}
+#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 *pi32)
+{
+ return (int32_t)ASMAtomicDecU32((uint32_t volatile *)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 && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(uint64_t) ASMAtomicDecU64(uint64_t volatile *pu64);
+#else
+DECLINLINE(uint64_t) ASMAtomicDecU64(uint64_t volatile *pu64)
+{
+# if RT_INLINE_ASM_USES_INTRIN && defined(RT_ARCH_AMD64)
+ uint64_t u64 = _InterlockedDecrement64((__int64 volatile *)pu64);
+ return u64;
+
+# 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");
+ return u64-1;
+# 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 *pi64)
+{
+ return (int64_t)ASMAtomicDecU64((uint64_t volatile *)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(int64_t) ASMAtomicDecZ(size_t volatile *pcb)
+{
+#if ARCH_BITS == 64
+ return ASMAtomicDecU64((uint64_t volatile *)pcb);
+#elif ARCH_BITS == 32
+ return ASMAtomicDecU32((uint32_t volatile *)pcb);
+#elif ARCH_BITS == 16
+ return ASMAtomicDecU16((uint16_t volatile *)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 && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(void) ASMAtomicOrU32(uint32_t volatile *pu32, uint32_t u32);
+#else
+DECLINLINE(void) ASMAtomicOrU32(uint32_t volatile *pu32, uint32_t u32)
+{
+# if RT_INLINE_ASM_USES_INTRIN
+ _InterlockedOr((long volatile *)pu32, (long)u32);
+
+# elif RT_INLINE_ASM_GNU_STYLE
+ __asm__ __volatile__("lock; orl %1, %0\n\t"
+ : "=m" (*pu32)
+ : "ir" (u32),
+ "m" (*pu32));
+# 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
+}
+#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 *pi32, int32_t i32)
+{
+ ASMAtomicOrU32((uint32_t volatile *)pi32, 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 && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(void) ASMAtomicOrU64(uint64_t volatile *pu64, uint64_t u64);
+#else
+DECLINLINE(void) ASMAtomicOrU64(uint64_t volatile *pu64, uint64_t u64)
+{
+# if RT_INLINE_ASM_USES_INTRIN && defined(RT_ARCH_AMD64)
+ _InterlockedOr64((__int64 volatile *)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));
+# 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 *pi64, int64_t i64)
+{
+ ASMAtomicOrU64((uint64_t volatile *)pi64, 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 && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(void) ASMAtomicAndU32(uint32_t volatile *pu32, uint32_t u32);
+#else
+DECLINLINE(void) ASMAtomicAndU32(uint32_t volatile *pu32, uint32_t u32)
+{
+# if RT_INLINE_ASM_USES_INTRIN
+ _InterlockedAnd((long volatile *)pu32, u32);
+
+# elif RT_INLINE_ASM_GNU_STYLE
+ __asm__ __volatile__("lock; andl %1, %0\n\t"
+ : "=m" (*pu32)
+ : "ir" (u32),
+ "m" (*pu32));
+# 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
+}
+#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 *pi32, int32_t i32)
+{
+ ASMAtomicAndU32((uint32_t volatile *)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 && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(void) ASMAtomicAndU64(uint64_t volatile *pu64, uint64_t u64);
+#else
+DECLINLINE(void) ASMAtomicAndU64(uint64_t volatile *pu64, uint64_t u64)
+{
+# if RT_INLINE_ASM_USES_INTRIN && defined(RT_ARCH_AMD64)
+ _InterlockedAnd64((__int64 volatile *)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));
+# 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 *pi64, int64_t i64)
+{
+ ASMAtomicAndU64((uint64_t volatile *)pi64, (uint64_t)i64);
+}
+
+
+/**
+ * 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
+DECLASM(void) ASMAtomicUoOrU32(uint32_t volatile *pu32, uint32_t u32);
+#else
+DECLINLINE(void) ASMAtomicUoOrU32(uint32_t volatile *pu32, uint32_t u32)
+{
+# if RT_INLINE_ASM_GNU_STYLE
+ __asm__ __volatile__("orl %1, %0\n\t"
+ : "=m" (*pu32)
+ : "ir" (u32),
+ "m" (*pu32));
+# else
+ __asm
+ {
+ mov eax, [u32]
+# ifdef RT_ARCH_AMD64
+ mov rdx, [pu32]
+ or [rdx], eax
+# else
+ mov edx, [pu32]
+ or [edx], eax
+# endif
+ }
+# endif
+}
+#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 *pi32, int32_t i32)
+{
+ ASMAtomicUoOrU32((uint32_t volatile *)pi32, 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
+DECLASM(void) ASMAtomicUoOrU64(uint64_t volatile *pu64, uint64_t u64);
+#else
+DECLINLINE(void) ASMAtomicUoOrU64(uint64_t volatile *pu64, uint64_t u64)
+{
+# if RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64)
+ __asm__ __volatile__("orq %1, %q0\n\t"
+ : "=m" (*pu64)
+ : "r" (u64),
+ "m" (*pu64));
+# 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 *pi64, int64_t i64)
+{
+ ASMAtomicUoOrU64((uint64_t volatile *)pi64, 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
+DECLASM(void) ASMAtomicUoAndU32(uint32_t volatile *pu32, uint32_t u32);
+#else
+DECLINLINE(void) ASMAtomicUoAndU32(uint32_t volatile *pu32, uint32_t u32)
+{
+# if RT_INLINE_ASM_GNU_STYLE
+ __asm__ __volatile__("andl %1, %0\n\t"
+ : "=m" (*pu32)
+ : "ir" (u32),
+ "m" (*pu32));
+# else
+ __asm
+ {
+ mov eax, [u32]
+# ifdef RT_ARCH_AMD64
+ mov rdx, [pu32]
+ and [rdx], eax
+# else
+ mov edx, [pu32]
+ and [edx], eax
+# endif
+ }
+# endif
+}
+#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 *pi32, int32_t i32)
+{
+ ASMAtomicUoAndU32((uint32_t volatile *)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
+DECLASM(void) ASMAtomicUoAndU64(uint64_t volatile *pu64, uint64_t u64);
+#else
+DECLINLINE(void) ASMAtomicUoAndU64(uint64_t volatile *pu64, uint64_t u64)
+{
+# if RT_INLINE_ASM_GNU_STYLE && defined(RT_ARCH_AMD64)
+ __asm__ __volatile__("andq %1, %0\n\t"
+ : "=m" (*pu64)
+ : "r" (u64),
+ "m" (*pu64));
+# 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 *pi64, int64_t i64)
+{
+ ASMAtomicUoAndU64((uint64_t volatile *)pi64, (uint64_t)i64);
+}
+
+
+/**
+ * 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
+DECLASM(uint32_t) ASMAtomicUoIncU32(uint32_t volatile *pu32);
+#else
+DECLINLINE(uint32_t) ASMAtomicUoIncU32(uint32_t volatile *pu32)
+{
+ 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");
+ 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
+}
+#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
+DECLASM(uint32_t) ASMAtomicUoDecU32(uint32_t volatile *pu32);
+#else
+DECLINLINE(uint32_t) ASMAtomicUoDecU32(uint32_t volatile *pu32)
+{
+ 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");
+ 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
+}
+#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
+#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
+DECLASM(void) ASMMemZeroPage(volatile void *pv);
+# else
+DECLINLINE(void) ASMMemZeroPage(volatile void *pv)
+{
+# 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
+DECLASM(void) ASMMemZero32(volatile void *pv, size_t cb);
+#else
+DECLINLINE(void) ASMMemZero32(volatile void *pv, size_t cb)
+{
+# if RT_INLINE_ASM_USES_INTRIN
+# ifdef RT_ARCH_AMD64
+ if (!(cb & 7))
+ __stosq((unsigned __int64 *)pv, 0, cb / 8);
+ else
+# endif
+ __stosd((unsigned long *)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
+DECLASM(void) ASMMemFill32(volatile void *pv, size_t cb, uint32_t u32);
+#else
+DECLINLINE(void) ASMMemFill32(volatile void *pv, size_t cb, uint32_t u32)
+{
+# if RT_INLINE_ASM_USES_INTRIN
+# ifdef RT_ARCH_AMD64
+ if (!(cb & 7))
+ __stosq((unsigned __int64 *)pv, RT_MAKE_U64(u32, u32), cb / 8);
+ else
+# endif
+ __stosd((unsigned long *)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.
+ *
+ * @todo Fix name, it is a predicate function but it's not returning boolean!
+ */
+#if !defined(RDESKTOP) && (!defined(RT_OS_LINUX) || !defined(__KERNEL__))
+DECLASM(void *) ASMMemFirstNonZero(void const *pv, size_t cb);
+#else
+DECLINLINE(void *) ASMMemFirstNonZero(void const *pv, size_t cb)
+{
+ uint8_t const *pb = (uint8_t const *)pv;
+ for (; cb; cb--, pb++)
+ if (RT_LIKELY(*pb == 0))
+ { /* likely */ }
+ else
+ return (void *)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 *pv, size_t cb)
+{
+ 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 *pvPage)
+{
+# 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));
+ return uAX.f;
+# else
+ uintptr_t const *puPtr = (uintptr_t const *)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 *pv, size_t cb, uint8_t u8);
+#else
+DECLINLINE(void *) ASMMemFirstMismatchingU8(void const *pv, size_t cb, uint8_t u8)
+{
+ uint8_t const *pb = (uint8_t const *)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 *pv, size_t cb, uint8_t u8)
+{
+ 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 *) ASMMemFirstMismatchingU32(void const *pv, size_t cb, uint32_t u32)
+{
+/** @todo rewrite this in inline assembly? */
+ uint32_t const *pu32 = (uint32_t const *)pv;
+ for (; cb; cb -= 4, pu32++)
+ if (RT_LIKELY(*pu32 == u32))
+ { /* likely */ }
+ else
+ return (uint32_t *)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
+DECLASM(uint8_t) ASMProbeReadByte(const void *pvByte);
+#else
+DECLINLINE(uint8_t) ASMProbeReadByte(const void *pvByte)
+{
+ /** @todo verify that the compiler actually doesn't optimize this away. (intel & gcc) */
+ uint8_t u8;
+# if RT_INLINE_ASM_GNU_STYLE
+ __asm__ __volatile__("movb (%1), %0\n\t"
+ : "=r" (u8)
+ : "r" (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;
+}
+#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 *pvBuf, size_t cbBuf)
+{
+ /** @todo verify that the compiler actually doesn't optimize this away. (intel & gcc) */
+ /* the first byte */
+ const uint8_t *pu8 = (const uint8_t *)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);
+}
+
+
+
+/** @defgroup grp_inline_bits Bit Operations
+ * @{
+ */
+
+
+/**
+ * Sets a bit in a bitmap.
+ *
+ * @param pvBitmap Pointer to the bitmap. 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 && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(void) ASMBitSet(volatile void *pvBitmap, int32_t iBit);
+#else
+DECLINLINE(void) ASMBitSet(volatile void *pvBitmap, int32_t iBit)
+{
+# if RT_INLINE_ASM_USES_INTRIN
+ _bittestandset((long *)pvBitmap, iBit);
+
+# elif RT_INLINE_ASM_GNU_STYLE
+ __asm__ __volatile__("btsl %1, %0"
+ : "=m" (*(volatile long *)pvBitmap)
+ : "Ir" (iBit),
+ "m" (*(volatile long *)pvBitmap)
+ : "memory");
+# 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
+}
+#endif
+
+
+/**
+ * Atomically sets a bit in a bitmap, ordered.
+ *
+ * @param pvBitmap Pointer to the bitmap. 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 && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(void) ASMAtomicBitSet(volatile void *pvBitmap, int32_t iBit);
+#else
+DECLINLINE(void) ASMAtomicBitSet(volatile void *pvBitmap, int32_t iBit)
+{
+ AssertMsg(!((uintptr_t)pvBitmap & 3), ("address %p not 32-bit aligned", pvBitmap));
+# if RT_INLINE_ASM_USES_INTRIN
+ _interlockedbittestandset((long *)pvBitmap, iBit);
+# elif RT_INLINE_ASM_GNU_STYLE
+ __asm__ __volatile__("lock; btsl %1, %0"
+ : "=m" (*(volatile long *)pvBitmap)
+ : "Ir" (iBit),
+ "m" (*(volatile long *)pvBitmap)
+ : "memory");
+# 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
+}
+#endif
+
+
+/**
+ * Clears a bit in a bitmap.
+ *
+ * @param pvBitmap Pointer to the bitmap.
+ * @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 && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(void) ASMBitClear(volatile void *pvBitmap, int32_t iBit);
+#else
+DECLINLINE(void) ASMBitClear(volatile void *pvBitmap, int32_t iBit)
+{
+# if RT_INLINE_ASM_USES_INTRIN
+ _bittestandreset((long *)pvBitmap, iBit);
+
+# elif RT_INLINE_ASM_GNU_STYLE
+ __asm__ __volatile__("btrl %1, %0"
+ : "=m" (*(volatile long *)pvBitmap)
+ : "Ir" (iBit),
+ "m" (*(volatile long *)pvBitmap)
+ : "memory");
+# 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
+}
+#endif
+
+
+/**
+ * Atomically clears a bit in a bitmap, ordered.
+ *
+ * @param pvBitmap Pointer to the bitmap. 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
+DECLASM(void) ASMAtomicBitClear(volatile void *pvBitmap, int32_t iBit);
+#else
+DECLINLINE(void) ASMAtomicBitClear(volatile void *pvBitmap, int32_t iBit)
+{
+ AssertMsg(!((uintptr_t)pvBitmap & 3), ("address %p not 32-bit aligned", pvBitmap));
+# if RT_INLINE_ASM_GNU_STYLE
+ __asm__ __volatile__("lock; btrl %1, %0"
+ : "=m" (*(volatile long *)pvBitmap)
+ : "Ir" (iBit),
+ "m" (*(volatile long *)pvBitmap)
+ : "memory");
+# 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
+}
+#endif
+
+
+/**
+ * Toggles a bit in a bitmap.
+ *
+ * @param pvBitmap Pointer to the bitmap.
+ * @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 && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(void) ASMBitToggle(volatile void *pvBitmap, int32_t iBit);
+#else
+DECLINLINE(void) ASMBitToggle(volatile void *pvBitmap, int32_t iBit)
+{
+# if RT_INLINE_ASM_USES_INTRIN
+ _bittestandcomplement((long *)pvBitmap, iBit);
+# elif RT_INLINE_ASM_GNU_STYLE
+ __asm__ __volatile__("btcl %1, %0"
+ : "=m" (*(volatile long *)pvBitmap)
+ : "Ir" (iBit),
+ "m" (*(volatile long *)pvBitmap)
+ : "memory");
+# 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
+}
+#endif
+
+
+/**
+ * Atomically toggles a bit in a bitmap, ordered.
+ *
+ * @param pvBitmap Pointer to the bitmap. 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
+DECLASM(void) ASMAtomicBitToggle(volatile void *pvBitmap, int32_t iBit);
+#else
+DECLINLINE(void) ASMAtomicBitToggle(volatile void *pvBitmap, int32_t iBit)
+{
+ AssertMsg(!((uintptr_t)pvBitmap & 3), ("address %p not 32-bit aligned", pvBitmap));
+# if RT_INLINE_ASM_GNU_STYLE
+ __asm__ __volatile__("lock; btcl %1, %0"
+ : "=m" (*(volatile long *)pvBitmap)
+ : "Ir" (iBit),
+ "m" (*(volatile long *)pvBitmap)
+ : "memory");
+# 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
+}
+#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.
+ * @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 && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(bool) ASMBitTestAndSet(volatile void *pvBitmap, int32_t iBit);
+#else
+DECLINLINE(bool) ASMBitTestAndSet(volatile void *pvBitmap, int32_t iBit)
+{
+ union { bool f; uint32_t u32; uint8_t u8; } rc;
+# if RT_INLINE_ASM_USES_INTRIN
+ rc.u8 = _bittestandset((long *)pvBitmap, iBit);
+
+# elif 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 *)pvBitmap)
+ : "Ir" (iBit),
+ "m" (*(volatile long *)pvBitmap)
+ : "memory");
+# 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
+ 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. 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 && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(bool) ASMAtomicBitTestAndSet(volatile void *pvBitmap, int32_t iBit);
+#else
+DECLINLINE(bool) ASMAtomicBitTestAndSet(volatile void *pvBitmap, int32_t iBit)
+{
+ 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 *)pvBitmap, iBit);
+# elif 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 *)pvBitmap)
+ : "Ir" (iBit),
+ "m" (*(volatile long *)pvBitmap)
+ : "memory");
+# 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
+ 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.
+ * @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 && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(bool) ASMBitTestAndClear(volatile void *pvBitmap, int32_t iBit);
+#else
+DECLINLINE(bool) ASMBitTestAndClear(volatile void *pvBitmap, int32_t iBit)
+{
+ union { bool f; uint32_t u32; uint8_t u8; } rc;
+# if RT_INLINE_ASM_USES_INTRIN
+ rc.u8 = _bittestandreset((long *)pvBitmap, iBit);
+
+# elif 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 *)pvBitmap)
+ : "Ir" (iBit),
+ "m" (*(volatile long *)pvBitmap)
+ : "memory");
+# 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
+ 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. 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 && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(bool) ASMAtomicBitTestAndClear(volatile void *pvBitmap, int32_t iBit);
+#else
+DECLINLINE(bool) ASMAtomicBitTestAndClear(volatile void *pvBitmap, int32_t iBit)
+{
+ 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 *)pvBitmap, iBit);
+
+# elif 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 *)pvBitmap)
+ : "Ir" (iBit),
+ "m" (*(volatile long *)pvBitmap)
+ : "memory");
+# 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
+ 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.
+ * @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 && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(bool) ASMBitTestAndToggle(volatile void *pvBitmap, int32_t iBit);
+#else
+DECLINLINE(bool) ASMBitTestAndToggle(volatile void *pvBitmap, int32_t iBit)
+{
+ union { bool f; uint32_t u32; uint8_t u8; } rc;
+# if RT_INLINE_ASM_USES_INTRIN
+ rc.u8 = _bittestandcomplement((long *)pvBitmap, iBit);
+
+# elif 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 *)pvBitmap)
+ : "Ir" (iBit),
+ "m" (*(volatile long *)pvBitmap)
+ : "memory");
+# 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
+ 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. 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
+DECLASM(bool) ASMAtomicBitTestAndToggle(volatile void *pvBitmap, int32_t iBit);
+#else
+DECLINLINE(bool) ASMAtomicBitTestAndToggle(volatile void *pvBitmap, int32_t iBit)
+{
+ 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_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 *)pvBitmap)
+ : "Ir" (iBit),
+ "m" (*(volatile long *)pvBitmap)
+ : "memory");
+# 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
+ 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.
+ * @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 && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(bool) ASMBitTest(const volatile void *pvBitmap, int32_t iBit);
+#else
+DECLINLINE(bool) ASMBitTest(const volatile void *pvBitmap, int32_t iBit)
+{
+ union { bool f; uint32_t u32; uint8_t u8; } rc;
+# if RT_INLINE_ASM_USES_INTRIN
+ rc.u32 = _bittest((long *)pvBitmap, iBit);
+# elif 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 *)pvBitmap),
+ "Ir" (iBit)
+ : "memory");
+# 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
+ return rc.f;
+}
+#endif
+
+
+/**
+ * Clears a bit range within a bitmap.
+ *
+ * @param pvBitmap Pointer to the bitmap.
+ * @param iBitStart The First bit to clear.
+ * @param iBitEnd The first bit not to clear.
+ */
+DECLINLINE(void) ASMBitClearRange(volatile void *pvBitmap, int32_t iBitStart, int32_t iBitEnd)
+{
+ if (iBitStart < iBitEnd)
+ {
+ volatile uint32_t *pu32 = (volatile uint32_t *)pvBitmap + (iBitStart >> 5);
+ int32_t iStart = iBitStart & ~31;
+ int32_t iEnd = iBitEnd & ~31;
+ if (iStart == iEnd)
+ *pu32 &= ((UINT32_C(1) << (iBitStart & 31)) - 1) | ~((UINT32_C(1) << (iBitEnd & 31)) - 1);
+ else
+ {
+ /* bits in first dword. */
+ if (iBitStart & 31)
+ {
+ *pu32 &= (UINT32_C(1) << (iBitStart & 31)) - 1;
+ pu32++;
+ iBitStart = iStart + 32;
+ }
+
+ /* whole dword. */
+ if (iBitStart != iEnd)
+ ASMMemZero32(pu32, (iEnd - iBitStart) >> 3);
+
+ /* bits in last dword. */
+ if (iBitEnd & 31)
+ {
+ pu32 = (volatile uint32_t *)pvBitmap + (iBitEnd >> 5);
+ *pu32 &= ~((UINT32_C(1) << (iBitEnd & 31)) - 1);
+ }
+ }
+ }
+}
+
+
+/**
+ * Sets a bit range within a bitmap.
+ *
+ * @param pvBitmap Pointer to the bitmap.
+ * @param iBitStart The First bit to set.
+ * @param iBitEnd The first bit not to set.
+ */
+DECLINLINE(void) ASMBitSetRange(volatile void *pvBitmap, int32_t iBitStart, int32_t iBitEnd)
+{
+ if (iBitStart < iBitEnd)
+ {
+ volatile uint32_t *pu32 = (volatile uint32_t *)pvBitmap + (iBitStart >> 5);
+ int32_t iStart = iBitStart & ~31;
+ int32_t iEnd = iBitEnd & ~31;
+ if (iStart == iEnd)
+ *pu32 |= ((UINT32_C(1) << (iBitEnd - iBitStart)) - 1) << (iBitStart & 31);
+ else
+ {
+ /* bits in first dword. */
+ if (iBitStart & 31)
+ {
+ *pu32 |= ~((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 *)pvBitmap + (iBitEnd >> 5);
+ *pu32 |= (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.
+ * @param cBits The number of bits in the bitmap. Multiple of 32.
+ */
+#if RT_INLINE_ASM_EXTERNAL
+DECLASM(int32_t) ASMBitFirstClear(const volatile void *pvBitmap, uint32_t cBits);
+#else
+DECLINLINE(int32_t) ASMBitFirstClear(const volatile void *pvBitmap, uint32_t cBits)
+{
+ 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));
+# 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.
+ * @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
+DECLASM(int) ASMBitNextClear(const volatile void *pvBitmap, uint32_t cBits, uint32_t iBitPrev);
+#else
+DECLINLINE(int) ASMBitNextClear(const volatile void *pvBitmap, uint32_t cBits, uint32_t iBitPrev)
+{
+ const volatile uint32_t *pau32Bitmap = (const volatile uint32_t *)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"
+ "1:\n\t"
+ : "=r" (iBit)
+ : "r" (u32));
+# else
+ __asm
+ {
+ mov edx, [u32]
+ bsf eax, edx
+ jnz done
+ mov eax, 0ffffffffh
+ done:
+ mov [iBit], eax
+ }
+# endif
+ if (iBit >= 0)
+ return iBit + 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.
+ * @param cBits The number of bits in the bitmap. Multiple of 32.
+ */
+#if RT_INLINE_ASM_EXTERNAL
+DECLASM(int32_t) ASMBitFirstSet(const volatile void *pvBitmap, uint32_t cBits);
+#else
+DECLINLINE(int32_t) ASMBitFirstSet(const volatile void *pvBitmap, uint32_t cBits)
+{
+ 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));
+# 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.
+ * @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
+DECLASM(int) ASMBitNextSet(const volatile void *pvBitmap, uint32_t cBits, uint32_t iBitPrev);
+#else
+DECLINLINE(int) ASMBitNextSet(const volatile void *pvBitmap, uint32_t cBits, uint32_t iBitPrev)
+{
+ const volatile uint32_t *pau32Bitmap = (const volatile uint32_t *)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"
+ "1:\n\t"
+ : "=r" (iBit)
+ : "r" (u32));
+# else
+ __asm
+ {
+ mov edx, [u32]
+ bsf eax, edx
+ jnz done
+ mov eax, 0ffffffffh
+ done:
+ mov [iBit], eax
+ }
+# endif
+ if (iBit >= 0)
+ return iBit + 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 && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(unsigned) ASMBitFirstSetU32(uint32_t u32);
+#else
+DECLINLINE(unsigned) ASMBitFirstSetU32(uint32_t u32)
+{
+# if RT_INLINE_ASM_USES_INTRIN
+ unsigned long iBit;
+ if (_BitScanForward(&iBit, u32))
+ iBit++;
+ else
+ iBit = 0;
+# elif 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));
+# else
+ uint32_t iBit;
+ _asm
+ {
+ bsf eax, [u32]
+ jnz found
+ xor eax, eax
+ jmp done
+ found:
+ inc eax
+ done:
+ mov [iBit], eax
+ }
+# 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)
+{
+ 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 && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(unsigned) ASMBitFirstSetU64(uint64_t u64);
+#else
+DECLINLINE(unsigned) ASMBitFirstSetU64(uint64_t u64)
+{
+# 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 && ARCH_BITS == 64
+ 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));
+# 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 && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(unsigned) ASMBitFirstSetU16(uint16_t u16);
+#else
+DECLINLINE(unsigned) ASMBitFirstSetU16(uint16_t u16)
+{
+ 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 && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(unsigned) ASMBitLastSetU32(uint32_t u32);
+#else
+DECLINLINE(unsigned) ASMBitLastSetU32(uint32_t u32)
+{
+# if RT_INLINE_ASM_USES_INTRIN
+ unsigned long iBit;
+ if (_BitScanReverse(&iBit, u32))
+ iBit++;
+ else
+ iBit = 0;
+# elif 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));
+# else
+ uint32_t iBit;
+ _asm
+ {
+ bsr eax, [u32]
+ jnz found
+ xor eax, eax
+ jmp done
+ found:
+ inc eax
+ done:
+ mov [iBit], eax
+ }
+# 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)
+{
+ 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 && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(unsigned) ASMBitLastSetU64(uint64_t u64);
+#else
+DECLINLINE(unsigned) ASMBitLastSetU64(uint64_t u64)
+{
+# 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 && ARCH_BITS == 64
+ 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));
+# 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 && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(unsigned) ASMBitLastSetU16(uint16_t u16);
+#else
+DECLINLINE(unsigned) ASMBitLastSetU16(uint16_t u16)
+{
+ return ASMBitLastSetU32((uint32_t)u16);
+}
+#endif
+
+
+/**
+ * Reverse the byte order of the given 16-bit integer.
+ *
+ * @returns Revert
+ * @param u16 16-bit integer value.
+ */
+#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(uint16_t) ASMByteSwapU16(uint16_t u16);
+#else
+DECLINLINE(uint16_t) ASMByteSwapU16(uint16_t u16)
+{
+# if RT_INLINE_ASM_USES_INTRIN
+ u16 = _byteswap_ushort(u16);
+# elif RT_INLINE_ASM_GNU_STYLE
+ __asm__ ("rorw $8, %0" : "=r" (u16) : "0" (u16));
+# else
+ _asm
+ {
+ mov ax, [u16]
+ ror ax, 8
+ mov [u16], ax
+ }
+# endif
+ return u16;
+}
+#endif
+
+
+/**
+ * Reverse the byte order of the given 32-bit integer.
+ *
+ * @returns Revert
+ * @param u32 32-bit integer value.
+ */
+#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
+DECLASM(uint32_t) ASMByteSwapU32(uint32_t u32);
+#else
+DECLINLINE(uint32_t) ASMByteSwapU32(uint32_t u32)
+{
+# if RT_INLINE_ASM_USES_INTRIN
+ u32 = _byteswap_ulong(u32);
+# elif 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;
+}
+#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)
+{
+#if defined(RT_ARCH_AMD64) && RT_INLINE_ASM_USES_INTRIN
+ u64 = _byteswap_uint64(u64);
+#else
+ u64 = (uint64_t)ASMByteSwapU32((uint32_t)u64) << 32
+ | (uint64_t)ASMByteSwapU32((uint32_t)(u64 >> 32));
+#endif
+ return u64;
+}
+
+
+/**
+ * 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__
+DECLASM(uint32_t) ASMRotateLeftU32(uint32_t u32, unsigned cShift);
+#else
+DECLINLINE(uint32_t) ASMRotateLeftU32(uint32_t u32, uint32_t cShift)
+{
+# 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));
+ 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__
+DECLASM(uint32_t) ASMRotateRightU32(uint32_t u32, unsigned cShift);
+#else
+DECLINLINE(uint32_t) ASMRotateRightU32(uint32_t u32, uint32_t cShift)
+{
+# 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));
+ 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)
+{
+#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));
+ 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));
+ 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)
+{
+#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));
+ 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));
+ return u64;
+#else
+ cShift &= 63;
+ return (u64 >> cShift) | (u64 << (64 - cShift));
+#endif
+}
+
+/** @} */
+
+
+/** @} */
+
+#endif
+
--- /dev/null
+/** @file
+ * IPRT - Assertions.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_assert_h
+#define ___iprt_assert_h
+
+#include <iprt/cdefs.h>
+#include <iprt/types.h>
+#include <iprt/stdarg.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.
+ *
+ * In addition there is a very special family AssertCompile that can be
+ * used for some limited compile-time checking, like structure sizes and member
+ * alignment. This family doesn't have the same variations.
+ *
+ *
+ * @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
+
+/**
+ * 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 assert message, 1st part. */
+extern RTDATADECL(char) g_szRTAssertMsg1[1024];
+/** The last assert message, 2nd part. */
+extern RTDATADECL(char) g_szRTAssertMsg2[4096];
+/** The last assert message, expression. */
+extern RTDATADECL(const char * volatile) g_pszRTAssertExpr;
+/** The last assert message, file name. */
+extern RTDATADECL(const char * volatile) g_pszRTAssertFile;
+/** The last assert message, line number. */
+extern RTDATADECL(uint32_t volatile) g_u32RTAssertLine;
+/** The last assert 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 Compile time assertions.
+ *
+ * These assertions are used to check structure sizes, member/size alignments
+ * and similar compile time expressions.
+ *
+ * @{
+ */
+
+/**
+ * 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 uses this.
+ */
+#ifdef __GNUC__
+RT_C_DECLS_BEGIN
+#endif
+extern int RTASSERTVAR[1];
+#ifdef __GNUC__
+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) extern int RTASSERTVAR[1] __attribute__((__unused__)), RTASSERTVAR[(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
+# define AssertCompile(expr) static_assert(!!(expr), #expr)
+#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)
+#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))
+
+/** @} */
+
+
+
+/** @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)
+# define RTAssertMsg2Weak if (1) {} else RTAssertMsg2Weak
+#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__, __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__, __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__, __PRETTY_FUNCTION__); \
+ RTAssertPanic(); \
+ break; \
+ } else do {} while (0)
+#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__, __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__, __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__, __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__, __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__, __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__, __PRETTY_FUNCTION__); \
+ RTAssertMsg2Weak a; \
+ RTAssertPanic(); \
+ break; \
+ } else do {} while (0)
+#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__, __PRETTY_FUNCTION__); \
+ RTAssertMsg2Weak a; \
+ RTAssertPanic(); \
+ stmt; \
+ break; \
+ } else do {} while (0)
+#else
+# define AssertMsgBreakStmt(expr, a, stmt) \
+ if (RT_LIKELY(!!(expr))) \
+ { /* likely */ } \
+ else if (1) \
+ { \
+ stmt; \
+ break; \
+ } else do {} while (0)
+#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__, __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__, __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__, __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__, __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__, __PRETTY_FUNCTION__); \
+ RTAssertPanic(); \
+ break; \
+ } else do {} while (0)
+#else
+# define AssertFailedBreak() \
+ if (1) \
+ break; \
+ else do {} while (0)
+#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__, __PRETTY_FUNCTION__); \
+ RTAssertPanic(); \
+ stmt; \
+ break; \
+ } else do {} while (0)
+#else
+# define AssertFailedBreakStmt(stmt) \
+ if (1) { \
+ stmt; \
+ break; \
+ } else do {} while (0)
+#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__, __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__, __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__, __PRETTY_FUNCTION__); \
+ RTAssertMsg2Weak a; \
+ RTAssertPanic(); \
+ break; \
+ } else do {} while (0)
+#else
+# define AssertMsgFailedBreak(a) \
+ if (1) \
+ break; \
+ else do {} while (0)
+#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__, __PRETTY_FUNCTION__); \
+ RTAssertMsg2Weak a; \
+ RTAssertPanic(); \
+ stmt; \
+ break; \
+ } else do {} while (0)
+#else
+# define AssertMsgFailedBreakStmt(a, stmt) \
+ if (1) { \
+ stmt; \
+ break; \
+ } else do {} while (0)
+#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__, __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__, __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__, __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__, __PRETTY_FUNCTION__); \
+ RTAssertPanic(); \
+ break; \
+ } \
+ else do {} while (0)
+
+/** @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__, __PRETTY_FUNCTION__); \
+ RTAssertPanic(); \
+ stmt; \
+ break; \
+ } else do {} 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__, __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__, __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__, __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__, __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__, __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__, __PRETTY_FUNCTION__); \
+ RTAssertLogRelMsg2(a); \
+ RTAssertPanic(); \
+ break; \
+ } \
+ else do {} while (0)
+
+/** @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__, __PRETTY_FUNCTION__); \
+ RTAssertLogRelMsg2(a); \
+ RTAssertPanic(); \
+ stmt; \
+ break; \
+ } else do {} while (0)
+
+/** @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__, __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__, __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__, __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__, __PRETTY_FUNCTION__); \
+ RTAssertPanic(); \
+ break; \
+ } else do {} while (0)
+
+/** @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__, __PRETTY_FUNCTION__); \
+ RTAssertPanic(); \
+ stmt; \
+ break; \
+ } else do {} while (0)
+
+/** @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__, __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__, __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__, __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__, __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__, __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__, __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__, __PRETTY_FUNCTION__); \
+ RTAssertLogRelMsg2(a); \
+ RTAssertPanic(); \
+ break; \
+ } else do {} while (0)
+
+/** @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__, __PRETTY_FUNCTION__); \
+ RTAssertLogRelMsg2(a); \
+ RTAssertPanic(); \
+ stmt; \
+ break; \
+ } else do {} while (0)
+
+/** @} */
+
+
+
+/** @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).
+ */
+#define RTAssertReleasePanic() do { RTAssertShouldPanic(); RTAssertDoPanic(); } while (0)
+
+
+/** @def AssertRelease
+ * Assert that an expression is true. If it's not hit a breakpoint.
+ *
+ * @param expr Expression which should be true.
+ */
+#define AssertRelease(expr) \
+ do { \
+ if (RT_LIKELY(!!(expr))) \
+ { /* likely */ } \
+ else \
+ { \
+ RTAssertMsg1Weak(#expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \
+ RTAssertReleasePanic(); \
+ } \
+ } while (0)
+
+/** @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.
+ */
+#define AssertReleaseReturn(expr, rc) \
+ do { \
+ if (RT_LIKELY(!!(expr))) \
+ { /* likely */ } \
+ else \
+ { \
+ RTAssertMsg1Weak(#expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \
+ RTAssertReleasePanic(); \
+ return (rc); \
+ } \
+ } while (0)
+
+/** @def AssertReleaseReturnVoid
+ * Assert that an expression is true, hit a breakpoint and return if it isn't.
+ *
+ * @param expr Expression which should be true.
+ */
+#define AssertReleaseReturnVoid(expr) \
+ do { \
+ if (RT_LIKELY(!!(expr))) \
+ { /* likely */ } \
+ else \
+ { \
+ RTAssertMsg1Weak(#expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \
+ RTAssertReleasePanic(); \
+ return; \
+ } \
+ } while (0)
+
+
+/** @def AssertReleaseBreak
+ * Assert that an expression is true, hit a breakpoint and break if it isn't.
+ *
+ * @param expr Expression which should be true.
+ */
+#define AssertReleaseBreak(expr) \
+ if (RT_LIKELY(!!(expr))) \
+ { /* likely */ } \
+ else if (1) \
+ { \
+ RTAssertMsg1Weak(#expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \
+ RTAssertReleasePanic(); \
+ break; \
+ } else do {} while (0)
+
+/** @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.
+ */
+#define AssertReleaseBreakStmt(expr, stmt) \
+ if (RT_LIKELY(!!(expr))) \
+ { /* likely */ } \
+ else if (1) \
+ { \
+ RTAssertMsg1Weak(#expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \
+ RTAssertReleasePanic(); \
+ stmt; \
+ break; \
+ } else do {} while (0)
+
+
+/** @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).
+ */
+#define AssertReleaseMsg(expr, a) \
+ do { \
+ if (RT_LIKELY(!!(expr))) \
+ { /* likely */ } \
+ else \
+ { \
+ RTAssertMsg1Weak(#expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \
+ RTAssertMsg2Weak a; \
+ RTAssertReleasePanic(); \
+ } \
+ } while (0)
+
+/** @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.
+ */
+#define AssertReleaseMsgReturn(expr, a, rc) \
+ do { \
+ if (RT_LIKELY(!!(expr))) \
+ { /* likely */ } \
+ else \
+ { \
+ RTAssertMsg1Weak(#expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \
+ RTAssertMsg2Weak a; \
+ RTAssertReleasePanic(); \
+ return (rc); \
+ } \
+ } while (0)
+
+/** @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).
+ */
+#define AssertReleaseMsgReturnVoid(expr, a) \
+ do { \
+ if (RT_LIKELY(!!(expr))) \
+ { /* likely */ } \
+ else \
+ { \
+ RTAssertMsg1Weak(#expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \
+ RTAssertMsg2Weak a; \
+ RTAssertReleasePanic(); \
+ return; \
+ } \
+ } while (0)
+
+
+/** @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).
+ */
+#define AssertReleaseMsgBreak(expr, a) \
+ if (RT_LIKELY(!!(expr))) \
+ { /* likely */ } \
+ else if (1) \
+ { \
+ RTAssertMsg1Weak(#expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \
+ RTAssertMsg2Weak a; \
+ RTAssertReleasePanic(); \
+ break; \
+ } else do {} while (0)
+
+/** @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.
+ */
+#define AssertReleaseMsgBreakStmt(expr, a, stmt) \
+ if (RT_LIKELY(!!(expr))) \
+ { /* likely */ } \
+ else if (1) \
+ { \
+ RTAssertMsg1Weak(#expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \
+ RTAssertMsg2Weak a; \
+ RTAssertReleasePanic(); \
+ stmt; \
+ break; \
+ } else do {} while (0)
+
+
+/** @def AssertReleaseFailed
+ * An assertion failed, hit a breakpoint.
+ */
+#define AssertReleaseFailed() \
+ do { \
+ RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, __PRETTY_FUNCTION__); \
+ RTAssertReleasePanic(); \
+ } while (0)
+
+/** @def AssertReleaseFailedReturn
+ * An assertion failed, hit a breakpoint and return.
+ *
+ * @param rc What is to be presented to return.
+ */
+#define AssertReleaseFailedReturn(rc) \
+ do { \
+ RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, __PRETTY_FUNCTION__); \
+ RTAssertReleasePanic(); \
+ return (rc); \
+ } while (0)
+
+/** @def AssertReleaseFailedReturnVoid
+ * An assertion failed, hit a breakpoint and return.
+ */
+#define AssertReleaseFailedReturnVoid() \
+ do { \
+ RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, __PRETTY_FUNCTION__); \
+ RTAssertReleasePanic(); \
+ return; \
+ } while (0)
+
+
+/** @def AssertReleaseFailedBreak
+ * An assertion failed, hit a breakpoint and break.
+ */
+#define AssertReleaseFailedBreak() \
+ if (1) { \
+ RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, __PRETTY_FUNCTION__); \
+ RTAssertReleasePanic(); \
+ break; \
+ } else do {} while (0)
+
+/** @def AssertReleaseFailedBreakStmt
+ * An assertion failed, hit a breakpoint and break.
+ *
+ * @param stmt Statement to execute before break.
+ */
+#define AssertReleaseFailedBreakStmt(stmt) \
+ if (1) { \
+ RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, __PRETTY_FUNCTION__); \
+ RTAssertReleasePanic(); \
+ stmt; \
+ break; \
+ } else do {} while (0)
+
+
+/** @def AssertReleaseMsgFailed
+ * An assertion failed, print a message and hit a breakpoint.
+ *
+ * @param a printf argument list (in parenthesis).
+ */
+#define AssertReleaseMsgFailed(a) \
+ do { \
+ RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \
+ RTAssertMsg2Weak a; \
+ RTAssertReleasePanic(); \
+ } while (0)
+
+/** @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.
+ */
+#define AssertReleaseMsgFailedReturn(a, rc) \
+ do { \
+ RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, __PRETTY_FUNCTION__); \
+ RTAssertMsg2Weak a; \
+ RTAssertReleasePanic(); \
+ return (rc); \
+ } while (0)
+
+/** @def AssertReleaseMsgFailedReturnVoid
+ * An assertion failed, print a message, hit a breakpoint and return.
+ *
+ * @param a printf argument list (in parenthesis).
+ */
+#define AssertReleaseMsgFailedReturnVoid(a) \
+ do { \
+ RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, __PRETTY_FUNCTION__); \
+ RTAssertMsg2Weak a; \
+ RTAssertReleasePanic(); \
+ return; \
+ } while (0)
+
+
+/** @def AssertReleaseMsgFailedBreak
+ * An assertion failed, print a message, hit a breakpoint and break.
+ *
+ * @param a printf argument list (in parenthesis).
+ */
+#define AssertReleaseMsgFailedBreak(a) \
+ if (1) { \
+ RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, __PRETTY_FUNCTION__); \
+ RTAssertMsg2Weak a; \
+ RTAssertReleasePanic(); \
+ break; \
+ } else do {} while (0)
+
+/** @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.
+ */
+#define AssertReleaseMsgFailedBreakStmt(a, stmt) \
+ if (1) { \
+ RTAssertMsg1Weak((const char *)0, __LINE__, __FILE__, __PRETTY_FUNCTION__); \
+ RTAssertMsg2Weak a; \
+ RTAssertReleasePanic(); \
+ stmt; \
+ break; \
+ } else do {} while (0)
+
+/** @} */
+
+
+
+/** @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__, __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__, __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(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(VALID_PTR(pv), ("%p\n", (pv)), rcRet)
+
+/** @def AssertPtrReturnVoid
+ * Asserts that a pointer is valid.
+ *
+ * @param pv The pointer.
+ */
+#define AssertPtrReturnVoid(pv) AssertMsgReturnVoid(VALID_PTR(pv), ("%p\n", (pv)))
+
+/** @def AssertPtrBreak
+ * Asserts that a pointer is valid.
+ *
+ * @param pv The pointer.
+ */
+#define AssertPtrBreak(pv) AssertMsgBreak(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(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(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(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(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(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(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
+
--- /dev/null
+/** @file
+ * IPRT - AVL Trees.
+ */
+
+/*
+ * Copyright (C) 2006-2017 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_avl_h
+#define ___iprt_avl_h
+
+#include <iprt/cdefs.h>
+#include <iprt/types.h>
+
+RT_C_DECLS_BEGIN
+
+/** @defgroup grp_rt_avl RTAvl - AVL Trees
+ * @ingroup grp_rt
+ * @{
+ */
+
+
+/** 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 DECLCALLBACK(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);
+
+/** @} */
+
+
+/** 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 DECLCALLBACK(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);
+
+/** @} */
+
+
+
+/** 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 DECLCALLBACK(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);
+
+/** @} */
+
+
+
+/** AVL tree of uint32_t
+ * @{
+ */
+
+/** AVL key type. */
+typedef uint32_t AVLU32KEY;
+
+/** AVL Core node. */
+typedef struct _AVLU32NodeCore
+{
+ AVLU32KEY Key; /**< Key value. */
+ struct _AVLU32NodeCore *pLeft; /**< Pointer to left leaf node. */
+ struct _AVLU32NodeCore *pRight; /**< Pointer to right leaf node. */
+ unsigned char uchHeight; /**< Height of this tree: max(height(left), height(right)) + 1 */
+} AVLU32NODECORE, *PAVLU32NODECORE, **PPAVLU32NODECORE;
+
+/** A tree with void pointer keys. */
+typedef PAVLU32NODECORE AVLU32TREE;
+/** Pointer to a tree with void pointer keys. */
+typedef PPAVLU32NODECORE PAVLU32TREE;
+
+/** Callback function for AVLU32DoWithAll() & AVLU32Destroy().
+ * @returns IPRT status codes. */
+typedef DECLCALLBACK(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);
+
+/** @} */
+
+/**
+ * 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 DECLCALLBACK(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);
+
+/** @} */
+
+
+/** 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 DECLCALLBACK(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);
+
+/** @} */
+
+
+
+/** 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 void pointer keys. */
+typedef PAVLRU64NODECORE AVLRU64TREE;
+/** Pointer to a tree with void pointer keys. */
+typedef PPAVLRU64NODECORE PAVLRU64TREE;
+
+/** Callback function for AVLRU64DoWithAll().
+ * @returns IPRT status codes. */
+typedef DECLCALLBACK(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);
+
+/** @} */
+
+
+
+/** 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 DECLCALLBACK(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);
+
+/** @} */
+
+
+/** 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 DECLCALLBACK(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);
+
+/** @} */
+
+
+/** 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 DECLCALLBACK(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);
+
+/** @} */
+
+
+/** 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 DECLCALLBACK(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);
+
+/** @} */
+
+
+/** 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 DECLCALLBACK(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);
+
+/** @} */
+
+
+/** 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 DECLCALLBACK(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);
+
+/** @} */
+
+
+/** 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 DECLCALLBACK(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);
+
+/** @} */
+
+
+/** 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 DECLCALLBACK(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);
+
+/** @} */
+
+
+/** 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 DECLCALLBACK(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);
+
+/** @} */
+
+
+/** 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 DECLCALLBACK(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);
+
+/** @} */
+
+
+
+/** 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 DECLCALLBACK(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);
+
+/** @} */
+
+
+/** 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 DECLCALLBACK(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);
+
+/** @} */
+
+
+/** 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 DECLCALLBACK(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);
+
+/** @} */
+
+/** 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 DECLCALLBACK(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);
+
+/** @} */
+
+
+/** 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 DECLCALLBACK(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
+
--- /dev/null
+/** @file
+ * IPRT - Common C and C++ definitions.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_cdefs_h
+#define ___iprt_cdefs_h
+
+
+/** @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 IN_RING0
+# define IN_RING3
+# define IN_RC
+# 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_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).
+ */
+#if !defined(RT_ARCH_X86) \
+ && !defined(RT_ARCH_AMD64) \
+ && !defined(RT_ARCH_SPARC) \
+ && !defined(RT_ARCH_SPARC64) \
+ && !defined(RT_ARCH_ARM)
+# 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(__arm__) || defined(__arm32__)
+# define RT_ARCH_ARM
+# 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_ARM) && defined(RT_ARCH_AMD64)
+# error "Both RT_ARCH_ARM and RT_ARCH_AMD64 cannot be defined at the same time!"
+#elif defined(RT_ARCH_ARM) && defined(RT_ARCH_X86)
+# error "Both RT_ARCH_ARM and RT_ARCH_X86 cannot be defined at the same time!"
+#elif defined(RT_ARCH_ARM) && defined(RT_ARCH_SPARC64)
+# error "Both RT_ARCH_ARM and RT_ARCH_SPARC64 cannot be defined at the same time!"
+#elif defined(RT_ARCH_ARM) && defined(RT_ARCH_SPARC)
+# error "Both RT_ARCH_ARM and RT_ARCH_SPARC cannot be defined at the same time!"
+#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_ARM) != 0) \
+ != 1
+# error "Exactly one RT_ARCH_XXX macro shall be defined"
+#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. */
+/** @} */
+
+/** @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 __X86__
+ * Indicates that we're compiling for the X86 architecture.
+ * @deprecated
+ */
+
+/** @def __AMD64__
+ * Indicates that we're compiling for the AMD64 architecture.
+ * @deprecated
+ */
+#if !defined(__X86__) && !defined(__AMD64__) && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86))
+# if defined(RT_ARCH_AMD64)
+# define __AMD64__
+# elif defined(RT_ARCH_X86)
+# 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_ARM)
+# 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) && !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)
+# 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_ARM)
+ # error "ARCH_BITS=64 but non-64-bit RT_ARCH_XXX defined."
+ #endif
+ #if !defined(RT_ARCH_AMD64) && !defined(RT_ARCH_SPARC64)
+ # 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)
+ # 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_ARM)
+ # 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_ARM)
+ # 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)
+# ifndef IN_RC
+# 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)
+# ifdef VBOX_WITH_64_BITS_GUESTS
+# 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
+
+/** @def GC_ARCH_BITS
+ * Defines the guest architecture bit count.
+ */
+#if !defined(GC_ARCH_BITS) || defined(DOXYGEN_RUNNING)
+# ifdef IN_RC
+# define GC_ARCH_BITS ARCH_BITS
+# else
+# define GC_ARCH_BITS 32
+# 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 GCType The GC type.
+ * @param R3Type The R3 type.
+ * @param R0Type The R0 type.
+ * @remark For pointers used only in one context use RCPTRTYPE(), R3R0PTRTYPE(), R3PTRTYPE() or R0PTRTYPE().
+ */
+#ifdef IN_RC
+# define CTXTYPE(GCType, R3Type, R0Type) GCType
+#elif defined(IN_RING3)
+# define CTXTYPE(GCType, R3Type, R0Type) R3Type
+#else
+# define CTXTYPE(GCType, R3Type, R0Type) R0Type
+#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 RCType The RC type.
+ */
+#define RCPTRTYPE(RCType) CTXTYPE(RCType, RTRCPTR, RTRCPTR)
+
+/** @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 R3R0Type The R3R0 type.
+ * @remarks This used to be called HCPTRTYPE.
+ */
+#define R3R0PTRTYPE(R3R0Type) CTXTYPE(RTHCPTR, R3R0Type, 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 R3Type The R3 type.
+ */
+#define R3PTRTYPE(R3Type) CTXTYPE(RTHCUINTPTR, 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 R0Type The R0 type.
+ */
+#define R0PTRTYPE(R0Type) CTXTYPE(RTHCUINTPTR, RTHCUINTPTR, 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 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 var Identifier name.
+ * @deprecated Use CTX_SUFF. Do NOT use this for new code.
+ */
+#ifdef IN_RC
+# define CTXSUFF(var) var##GC
+# define OTHERCTXSUFF(var) var##HC
+#else
+# define CTXSUFF(var) var##HC
+# define OTHERCTXSUFF(var) 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 var Identifier name.
+ * @deprecated Use CTX_SUFF. Do NOT use this for new code.
+ */
+#ifdef IN_RC
+# define CTXALLSUFF(var) var##GC
+#elif defined(IN_RING0)
+# define CTXALLSUFF(var) var##R0
+#else
+# define CTXALLSUFF(var) 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 var Identifier name.
+ *
+ * @remark This will replace CTXALLSUFF and CTXSUFF before long.
+ */
+#ifdef IN_RC
+# define CTX_SUFF(var) var##RC
+#elif defined(IN_RING0)
+# define CTX_SUFF(var) var##R0
+#else
+# define CTX_SUFF(var) 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 var Identifier name.
+ *
+ * @remark This will replace CTXALLSUFF and CTXSUFF before long.
+ */
+#ifdef IN_RING3
+# define CTX_SUFF_Z(var) var##R3
+#else
+# define CTX_SUFF_Z(var) 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 first First name.
+ * @param 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 first First name.
+ * @param last Surname.
+ * @deprecated use CTX_MID or CTX_MID_Z
+ */
+#ifdef IN_RC
+# define CTXMID(first, last) first##GC##last
+# define OTHERCTXMID(first, last) first##HC##last
+#else
+# define CTXMID(first, last) first##HC##last
+# define OTHERCTXMID(first, last) first##GC##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 first First name.
+ * @param last Surname.
+ * @deprecated use CTX_MID or CTX_MID_Z
+ */
+#ifdef IN_RC
+# define CTXALLMID(first, last) first##GC##last
+#elif defined(IN_RING0)
+# define CTXALLMID(first, last) first##R0##last
+#else
+# define CTXALLMID(first, last) first##R3##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 first First name.
+ * @param last Surname.
+ */
+#ifdef IN_RC
+# define CTX_MID(first, last) first##RC##last
+#elif defined(IN_RING0)
+# define CTX_MID(first, last) first##R0##last
+#else
+# define CTX_MID(first, last) first##R3##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 first First name.
+ * @param last Surname.
+ */
+#ifdef IN_RING3
+# define CTX_MID_Z(first, last) first##R3##last
+#else
+# define CTX_MID_Z(first, last) first##RZ##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 pR3String The R3 string. Only referenced in R3.
+ * @see R0STRING and GCSTRING
+ */
+#ifdef IN_RING3
+# define R3STRING(pR3String) (pR3String)
+#else
+# define R3STRING(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 pR0String The R0 string. Only referenced in R0.
+ * @see R3STRING and GCSTRING
+ */
+#ifdef IN_RING0
+# define R0STRING(pR0String) (pR0String)
+#else
+# define R0STRING(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 pRCString The RC string. Only referenced in RC.
+ * @see R3STRING, R0STRING
+ */
+#ifdef IN_RC
+# define RCSTRING(pRCString) (pRCString)
+#else
+# define RCSTRING(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 should not warn about deprecated
+ * declarations. */
+#if RT_GNUC_PREREQ(4, 6)
+# define RT_GCC_NO_WARN_DEPRECATED_BEGIN \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
+/** @def RT_GCC_NO_WARN_DEPRECATED_END
+ * Used to end a block of code where GCC should not warn about deprecated
+ * 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_WITH_80BIT_LONG_DOUBLE
+ * Macro that is defined if the compiler implements long double as the
+ * IEEE extended precision floating. */
+#if (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)) && !defined(RT_OS_WINDOWS)
+# define RT_COMPILER_WITH_80BIT_LONG_DOUBLE
+#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 RT_NO_THROW_PROTO
+ * 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. Put this between the closing parenthesis
+ * and the semicolon in function prototypes (and implementation if C++).
+ *
+ * @remarks May not work on C++ methods, mainly intented for C-style APIs.
+ *
+ * @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 use to have two
+ * macros, as the nothrow attribute is not for the function definition.
+ */
+#ifdef RT_EXCEPTIONS_ENABLED
+# ifdef __GNUC__
+# define RT_NO_THROW_PROTO __attribute__((__nothrow__))
+# else
+# define RT_NO_THROW_PROTO throw()
+# endif
+#else
+# define RT_NO_THROW_PROTO
+#endif
+
+/** @def RT_NO_THROW_DEF
+ * The counter part to RT_NO_THROW_PROTO that is added to the function
+ * definition.
+ */
+#if defined(RT_EXCEPTIONS_ENABLED) && !defined(__GNUC__)
+# define RT_NO_THROW_DEF RT_NO_THROW_PROTO
+#else
+# define RT_NO_THROW_DEF
+#endif
+
+/** @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 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 RT_MSC_PREREQ_EX(RT_MSC_VER_VC71, 0)
+# define RT_THROW(type)
+# elif RT_GNUC_PREREQ(7, 0)
+# define RT_THROW(type)
+# else
+# define RT_THROW(type) throw(type)
+# endif
+#else
+# define RT_THROW(type)
+#endif
+
+/** @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
+#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 type The return type of the function declaration.
+ */
+#if defined(_MSC_VER) || defined(RT_OS_OS2)
+# define DECLEXPORT(type) __declspec(dllexport) type
+#elif defined(RT_USE_VISIBILITY_DEFAULT)
+# define DECLEXPORT(type) __attribute__((visibility("default"))) type
+#else
+# define DECLEXPORT(type) type
+#endif
+
+/** @def DECLIMPORT
+ * How to declare an imported function.
+ * @param type The return type of the function declaration.
+ */
+#if defined(_MSC_VER) || (defined(RT_OS_OS2) && !defined(__IBMC__) && !defined(__IBMCPP__))
+# define DECLIMPORT(type) __declspec(dllimport) type
+#else
+# define DECLIMPORT(type) type
+#endif
+
+/** @def DECLHIDDEN
+ * How to declare a non-exported function or variable.
+ * @param type The return type of the function or the data type of the variable.
+ */
+#if !defined(RT_GCC_SUPPORTS_VISIBILITY_HIDDEN) || defined(RT_NO_VISIBILITY_HIDDEN)
+# define DECLHIDDEN(type) type
+#else
+# define DECLHIDDEN(type) __attribute__((visibility("hidden"))) type
+#endif
+
+/** @def DECL_HIDDEN_CONST
+ * Workaround for g++ warnings when applying the hidden attribute to a const
+ * definition. Use DECLHIDDEN for the declaration.
+ * @param a_Type The return type of the function or the data type of
+ * the variable.
+ */
+#if defined(__cplusplus) && defined(__GNUC__)
+# define DECL_HIDDEN_CONST(a_Type) a_Type
+#else
+# define DECL_HIDDEN_CONST(a_Type) DECLHIDDEN(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 type The return type of the function.
+ */
+#if defined(_MSC_VER)
+# define DECL_INVALID(type) __declspec(dllimport) type __stdcall
+#elif defined(__GNUC__) && defined(__cplusplus)
+# define DECL_INVALID(type) extern "C++" type
+#else
+# define DECL_INVALID(type) type
+#endif
+
+/** @def DECLASM
+ * How to declare an internal assembly function.
+ * @param type The return type of the function declaration.
+ */
+#ifdef __cplusplus
+# define DECLASM(type) extern "C" type RTCALL
+#else
+# define DECLASM(type) type RTCALL
+#endif
+
+/** @def DECLASMTYPE
+ * How to declare an internal assembly function type.
+ * @param type The return type of the function.
+ */
+#define DECLASMTYPE(type) type RTCALL
+
+/** @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
+ * EMR3DECL(DECL_NO_RETURN(void)) foo(void);
+ * @endcode
+ */
+#ifdef _MSC_VER
+# define DECL_NO_RETURN(type) __declspec(noreturn) type
+#elif defined(__GNUC__)
+# define DECL_NO_RETURN(type) __attribute__((noreturn)) type
+#else
+# define DECL_NO_RETURN(type) type
+#endif
+/** @deprecated Use DECL_NO_RETURN instead. */
+#define DECLNORETURN(type) DECL_NO_RETURN(type)
+
+/** @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
+ * EMR3DECL(DECL_RETURNS_TWICE(void)) MySetJmp(void);
+ * @endcode
+ */
+#if RT_GNUC_PREREQ(4, 1)
+# define DECL_RETURNS_TWICE(type) __attribute__((returns_twice)) type
+# else
+# define DECL_RETURNS_TWICE(type) type
+#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
+ * EMR3DECL(DECLWEAK(int)) foo;
+ * @endcode
+ */
+#if defined(__GNUC__)
+# define DECLWEAK(type) type __attribute__((weak))
+#else
+# define DECLWEAK(type) type
+#endif
+
+/** @def DECLCALLBACK
+ * How to declare an call back function type.
+ * @param type The return type of the function declaration.
+ */
+#define DECLCALLBACK(type) type RTCALL
+
+/** @def DECLCALLBACKPTR
+ * How to declare an call back function pointer.
+ * @param type The return type of the function declaration.
+ * @param name The name of the variable member.
+ */
+#if defined(__IBMC__) || defined(__IBMCPP__)
+# define DECLCALLBACKPTR(type, name) type (* RTCALL name)
+#else
+# define DECLCALLBACKPTR(type, name) type (RTCALL * name)
+#endif
+
+/** @def DECLCALLBACKMEMBER
+ * How to declare an call back function pointer member.
+ * @param type The return type of the function declaration.
+ * @param name The name of the struct/union/class member.
+ */
+#if defined(__IBMC__) || defined(__IBMCPP__)
+# define DECLCALLBACKMEMBER(type, name) type (* RTCALL name)
+#else
+# define DECLCALLBACKMEMBER(type, name) type (RTCALL * name)
+#endif
+
+/** @def DECLR3CALLBACKMEMBER
+ * How to declare an call back function pointer member - R3 Ptr.
+ * @param type The return type of the function declaration.
+ * @param name The name of the struct/union/class member.
+ * @param args The argument list enclosed in parentheses.
+ */
+#ifdef IN_RING3
+# define DECLR3CALLBACKMEMBER(type, name, args) DECLCALLBACKMEMBER(type, name) args
+#else
+# define DECLR3CALLBACKMEMBER(type, name, args) RTR3PTR name
+#endif
+
+/** @def DECLRCCALLBACKMEMBER
+ * How to declare an call back function pointer member - RC Ptr.
+ * @param type The return type of the function declaration.
+ * @param name The name of the struct/union/class member.
+ * @param args The argument list enclosed in parentheses.
+ */
+#ifdef IN_RC
+# define DECLRCCALLBACKMEMBER(type, name, args) DECLCALLBACKMEMBER(type, name) args
+#else
+# define DECLRCCALLBACKMEMBER(type, name, args) RTRCPTR name
+#endif
+
+/** @def DECLR0CALLBACKMEMBER
+ * How to declare an call back function pointer member - R0 Ptr.
+ * @param type The return type of the function declaration.
+ * @param name The name of the struct/union/class member.
+ * @param args The argument list enclosed in parentheses.
+ */
+#ifdef IN_RING0
+# define DECLR0CALLBACKMEMBER(type, name, args) DECLCALLBACKMEMBER(type, name) args
+#else
+# define DECLR0CALLBACKMEMBER(type, name, args) RTR0PTR name
+#endif
+
+/** @def DECLINLINE
+ * How to declare a function as inline.
+ * @param type The return type of the function declaration.
+ * @remarks Don't use this macro on C++ methods.
+ */
+#ifdef __GNUC__
+# define DECLINLINE(type) static __inline__ type
+#elif defined(__cplusplus)
+# define DECLINLINE(type) static inline type
+#elif defined(_MSC_VER)
+# define DECLINLINE(type) static _inline type
+#elif defined(__IBMC__)
+# define DECLINLINE(type) _Inline type
+#else
+# define DECLINLINE(type) inline type
+#endif
+
+
+/** @def DECL_FORCE_INLINE
+ * How to declare a function as inline and try convince the compiler to always
+ * inline it regardless of optimization switches.
+ * @param type 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(type) __attribute__((__always_inline__)) DECLINLINE(type)
+#elif defined(_MSC_VER)
+# define DECL_FORCE_INLINE(type) __forceinline type
+#else
+# define DECL_FORCE_INLINE(type) DECLINLINE(type)
+#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 type The return type of the function declaration.
+ * @remarks Don't use this macro on C++ methods.
+ */
+#ifdef __GNUC__
+# define DECL_NO_INLINE(scope,type) __attribute__((__noinline__)) scope type
+#elif defined(_MSC_VER)
+# define DECL_NO_INLINE(scope,type) __declspec(noinline) scope type
+#else
+# define DECL_NO_INLINE(scope,type) scope type
+#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(type)
+ * Runtime Library host context ring-0 export or import declaration.
+ * @param type 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.
+ */
+#ifdef IN_RT_R0
+# ifdef IN_RT_STATIC
+# define RTR0DECL(type) DECLHIDDEN(type) RTCALL
+# else
+# define RTR0DECL(type) DECLEXPORT(type) RTCALL
+# endif
+#else
+# define RTR0DECL(type) DECLIMPORT(type) 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(type)
+ * Runtime Library host context ring-3 export or import declaration.
+ * @param type 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.
+ */
+#ifdef IN_RT_R3
+# ifdef IN_RT_STATIC
+# define RTR3DECL(type) DECLHIDDEN(type) RTCALL
+# else
+# define RTR3DECL(type) DECLEXPORT(type) RTCALL
+# endif
+#else
+# define RTR3DECL(type) DECLIMPORT(type) 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(type)
+ * Runtime Library raw-mode context export or import declaration.
+ * @param type 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.
+ */
+#ifdef IN_RT_RC
+# ifdef IN_RT_STATIC
+# define RTRCDECL(type) DECLHIDDEN(type) RTCALL
+# else
+# define RTRCDECL(type) DECLEXPORT(type) RTCALL
+# endif
+#else
+# define RTRCDECL(type) DECLIMPORT(type) RTCALL
+#endif
+
+/** @def RTDECL(type)
+ * Runtime Library export or import declaration.
+ * Functions declared using this macro exists in all contexts.
+ * @param type 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.
+ */
+#if defined(IN_RT_R3) || defined(IN_RT_RC) || defined(IN_RT_R0)
+# ifdef IN_RT_STATIC
+# define RTDECL(type) DECLHIDDEN(type) RTCALL
+# else
+# define RTDECL(type) DECLEXPORT(type) RTCALL
+# endif
+#else
+# define RTDECL(type) DECLIMPORT(type) RTCALL
+#endif
+
+/** @def RTDATADECL(type)
+ * Runtime Library export or import declaration.
+ * Data declared using this macro exists in all contexts.
+ * @param 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(type)
+ * Definition of a const variable. See DECL_HIDDEN_CONST.
+ * @param 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(type) DECLHIDDEN(type)
+# define RT_DECL_DATA_CONST(type) DECL_HIDDEN_CONST(type)
+# else
+# define RTDATADECL(type) DECLEXPORT(type)
+# if defined(__cplusplus) && defined(__GNUC__)
+# define RT_DECL_DATA_CONST(type) type
+# else
+# define RT_DECL_DATA_CONST(type) DECLEXPORT(type)
+# endif
+# endif
+#else
+# define RTDATADECL(type) DECLIMPORT(type)
+# define RT_DECL_DATA_CONST(type) DECLIMPORT(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.
+ */
+#ifndef RT_WITHOUT_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
+
+
+
+/** @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_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.
+ *
+ * This differs from the usual offsetof() in that it's not relying on builtin
+ * compiler stuff and thus can use variables in arrays the structure may
+ * contain. This is useful to determine the sizes of structures ending
+ * with a variable length field. For gcc >= 4.4 see @bugref{7775}.
+ *
+ * @returns offset into the structure of the specified member. signed.
+ * @param type Structure type.
+ * @param member Member.
+ */
+#if defined(__cplusplus) && RT_GNUC_PREREQ(4, 4)
+# define RT_OFFSETOF(type, member) ( (int)(uintptr_t)&( ((type *)(void *)0x1000)->member) - 0x1000 )
+#else
+# define RT_OFFSETOF(type, member) ( (int)(uintptr_t)&( ((type *)(void *)0)->member) )
+#endif
+
+/** @def RT_UOFFSETOF
+ * Our own special offsetof() variant, returns an unsigned result.
+ *
+ * This differs from the usual offsetof() in that it's not relying on builtin
+ * compiler stuff and thus can use variables in arrays the structure may
+ * contain. This is useful to determine the sizes of structures ending
+ * with a variable length field. For gcc >= 4.4 see @bugref{7775}.
+ *
+ * @returns offset into the structure of the specified member. unsigned.
+ * @param type Structure type.
+ * @param member Member.
+ */
+#if defined(__cplusplus) && RT_GNUC_PREREQ(4, 4)
+# define RT_UOFFSETOF(type, member) ( (uintptr_t)&( ((type *)(void *)0x1000)->member) - 0x1000 )
+#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.
+ */
+#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.
+ */
+#define RT_UOFFSETOF_ADD(type, member, addend) ( (uintptr_t)&( ((type *)(void *)(uintptr_t)(addend))->member) )
+
+/** @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_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_FLEXIBLE_ARRAY
+ * What to up inside the square brackets when declaring a structure member
+ * with a flexible size.
+ *
+ * @note Use RT_UOFFSETOF() to calculate the structure size.
+ *
+ * @note Never to 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) && !RT_GNUC_PREREQ(7, 0)) /* gcc-7 warns again */\
+ || defined(__WATCOMC__) /* openwatcom 1.9 supports it, we don't care about older atm. */
+# define RT_FLEXIBLE_ARRAY
+# if defined(__cplusplus) && defined(_MSC_VER)
+# pragma warning(disable:4200) /* -wd4200 does not work with VS2010 */
+# 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_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
+
+/**
+ * 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) ( (a) & 0xff )
+/** @def RT_BYTE2
+ * Gets the second byte of something. */
+#define RT_BYTE2(a) ( ((a) >> 8) & 0xff )
+/** @def RT_BYTE3
+ * Gets the second byte of something. */
+#define RT_BYTE3(a) ( ((a) >> 16) & 0xff )
+/** @def RT_BYTE4
+ * Gets the fourth byte of something. */
+#define RT_BYTE4(a) ( ((a) >> 24) & 0xff )
+/** @def RT_BYTE5
+ * Gets the fifth byte of something. */
+#define RT_BYTE5(a) ( ((a) >> 32) & 0xff )
+/** @def RT_BYTE6
+ * Gets the sixth byte of something. */
+#define RT_BYTE6(a) ( ((a) >> 40) & 0xff )
+/** @def RT_BYTE7
+ * Gets the seventh byte of something. */
+#define RT_BYTE7(a) ( ((a) >> 48) & 0xff )
+/** @def RT_BYTE8
+ * Gets the eight byte of something. */
+#define RT_BYTE8(a) ( ((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 \
+ | (uint32_t)((uint8_t)(b3)) << 24 \
+ | (uint32_t)((uint8_t)(b2)) << 16 \
+ | (uint16_t)((uint8_t)(b1)) << 8 \
+ | (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 \
+ | (uint16_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 0
+# define RT_BSWAP_U64(u64) RT_BSWAP_U64_C(u64)
+#elif 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 0
+# define RT_BSWAP_U32(u32) RT_BSWAP_U32_C(u32)
+#elif 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 0
+# define RT_BSWAP_U16(u16) RT_BSWAP_U16_C(u16)
+#elif 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_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_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_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_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)
+
+
+/*
+ * 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)
+/** @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). */
+# 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 hour expressed in nanoseconds (64-bit). */
+#define RT_NS_1HOUR UINT64_C(3600000000000)
+/** 1 minute expressed in nanoseconds (64-bit). */
+#define RT_NS_1MIN UINT64_C(60000000000)
+/** 45 second expressed in nanoseconds. */
+#define RT_NS_45SEC UINT64_C(45000000000)
+/** 30 second expressed in nanoseconds. */
+#define RT_NS_30SEC UINT64_C(30000000000)
+/** 20 second expressed in nanoseconds. */
+#define RT_NS_20SEC UINT64_C(20000000000)
+/** 15 second expressed in nanoseconds. */
+#define RT_NS_15SEC UINT64_C(15000000000)
+/** 10 second expressed in nanoseconds. */
+#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)
+/** 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 hour expressed in microseconds. */
+#define RT_US_1HOUR UINT32_C(3600000000)
+/** 1 minute expressed in microseconds. */
+#define RT_US_1MIN UINT32_C(60000000)
+/** 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)
+/** 1 minute expressed in microseconds - 64-bit type. */
+#define RT_US_1MIN_64 UINT64_C(60000000)
+/** 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 hour expressed in milliseconds. */
+#define RT_MS_1HOUR UINT32_C(3600000)
+/** 1 minute expressed in milliseconds. */
+#define RT_MS_1MIN UINT32_C(60000)
+/** 1 second expressed in milliseconds. */
+#define RT_MS_1SEC UINT32_C(1000)
+
+/** 1 hour expressed in milliseconds - 64-bit type. */
+#define RT_MS_1HOUR_64 UINT64_C(3600000)
+/** 1 minute expressed in milliseconds - 64-bit type. */
+#define RT_MS_1MIN_64 UINT64_C(60000)
+/** 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 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) )
+# else
+# define RT_VALID_PTR(ptr) ( (uintptr_t)(ptr) + 0x1000U >= 0x2000U \
+ && !((uintptr_t)(ptr) & 0xffff800000000000ULL) )
+# endif
+# else /* !IN_RING3 */
+# define RT_VALID_PTR(ptr) ( (uintptr_t)(ptr) + 0x1000U >= 0x2000U \
+ && ( ((uintptr_t)(ptr) & 0xffff800000000000ULL) == 0xffff800000000000ULL \
+ || ((uintptr_t)(ptr) & 0xffff800000000000ULL) == 0) )
+# 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_ARM)
+/* 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
+
+/** Old name for RT_VALID_PTR. */
+#define VALID_PTR(ptr) RT_VALID_PTR(ptr)
+
+/** @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)) \
+ && 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)
+
+
+/** @def __PRETTY_FUNCTION__
+ * With GNU C we'd like to use the builtin __PRETTY_FUNCTION__, so define that
+ * for the other compilers.
+ */
+#if !defined(__GNUC__) && !defined(__PRETTY_FUNCTION__)
+# ifdef _MSC_VER
+# 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(__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 the major MSC version if the compiler have and uses intrin.h.
+ * Otherwise it is 0. */
+#ifdef _MSC_VER
+# if _MSC_VER >= 1700 /* Visual C++ v11.0 / 2012 */
+# define RT_INLINE_ASM_USES_INTRIN 17
+# elif _MSC_VER >= 1600 /* Visual C++ v10.0 / 2010 */
+# define RT_INLINE_ASM_USES_INTRIN 16
+# elif _MSC_VER >= 1500 /* Visual C++ v9.0 / 2008 */
+# define RT_INLINE_ASM_USES_INTRIN 15
+# elif _MSC_VER >= 1400 /* Visual C++ v8.0 / 2005 */
+# define RT_INLINE_ASM_USES_INTRIN 14
+# endif
+#endif
+#ifndef RT_INLINE_ASM_USES_INTRIN
+# define RT_INLINE_ASM_USES_INTRIN 0
+#endif
+
+/** @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_FAR_DATA
+ * 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_FAR_DATA 1
+#else
+# define RT_FAR_DATA 0
+#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
+
--- /dev/null
+/** @file
+ * IPRT - CPU Set.
+ */
+
+/*
+ * Copyright (C) 2008-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_cpuset_h
+#define ___iprt_cpuset_h
+
+#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 + iBit;
+ }
+ }
+ return 0;
+}
+
+
+/** @} */
+
+RT_C_DECLS_END
+
+#endif
+
--- /dev/null
+/** @file
+ * IPRT - Simple character type classiciation and conversion.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_ctype_h
+#define ___iprt_ctype_h
+
+#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 - 0x2aU < 6U /* 2a..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 applictable.
+ *
+ * @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 applictable.
+ *
+ * @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
+
--- /dev/null
+/** @file
+ * IPRT - Status Codes.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_err_h
+#define ___iprt_err_h
+
+#include <iprt/cdefs.h>
+#include <iprt/types.h>
+#include <iprt/stdarg.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.
+ *
+ * @{
+ */
+
+/** @defgroup grp_rt_err_hlp Status Code Helpers
+ * @{
+ */
+
+#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)
+ : m_rc(rcObj.getValue())
+ {
+ }
+
+ /**
+ * Integer constructor used by RT_SUCCESS_NP.
+ *
+ * @param rc IPRT style status code.
+ */
+ RTErrStrictType(int32_t rc)
+ : 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
+ {
+ return m_rc >= 0;
+ }
+
+private:
+ /** @name Try ban a number of wrong types.
+ * @{ */
+ RTErrStrictType(uint8_t rc) : m_rc(-999) { NOREF(rc); }
+ RTErrStrictType(uint16_t rc) : m_rc(-999) { NOREF(rc); }
+ RTErrStrictType(uint32_t rc) : m_rc(-999) { NOREF(rc); }
+ RTErrStrictType(uint64_t rc) : m_rc(-999) { NOREF(rc); }
+ RTErrStrictType(int8_t rc) : m_rc(-999) { NOREF(rc); }
+ RTErrStrictType(int16_t rc) : m_rc(-999) { NOREF(rc); }
+ RTErrStrictType(int64_t rc) : m_rc(-999) { NOREF(rc); }
+ /** @todo fight long here - clashes with int32_t/int64_t on some platforms. */
+ /** @} */
+};
+#endif /* __cplusplus */
+
+
+/** @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(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) )
+
+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 uNativeCode errno code.
+ */
+RTDECL(int) RTErrConvertFromErrno(unsigned uNativeCode);
+
+/**
+ * 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);
+
+#ifdef IN_RING3
+
+/**
+ * iprt status code message.
+ */
+typedef struct RTSTATUSMSG
+{
+ /** Pointer to the short message string. */
+ const char *pszMsgShort;
+ /** Pointer to the full message string. */
+ const char *pszMsgFull;
+ /** Pointer to the define string. */
+ const char *pszDefine;
+ /** Status code number. */
+ int iCode;
+} RTSTATUSMSG;
+/** Pointer to iprt status code message. */
+typedef RTSTATUSMSG *PRTSTATUSMSG;
+/** Pointer to const iprt status code message. */
+typedef const RTSTATUSMSG *PCRTSTATUSMSG;
+
+/**
+ * Get the message structure corresponding to a given iprt status code.
+ *
+ * @returns Pointer to read-only message description.
+ * @param rc The status code.
+ */
+RTDECL(PCRTSTATUSMSG) RTErrGet(int rc);
+
+/**
+ * Get the define corresponding to a given iprt status code.
+ *
+ * @returns Pointer to read-only string with the \#define identifier.
+ * @param rc The status code.
+ */
+#define RTErrGetDefine(rc) (RTErrGet(rc)->pszDefine)
+
+/**
+ * Get the short description corresponding to a given iprt status code.
+ *
+ * @returns Pointer to read-only string with the description.
+ * @param rc The status code.
+ */
+#define RTErrGetShort(rc) (RTErrGet(rc)->pszMsgShort)
+
+/**
+ * Get the full description corresponding to a given iprt status code.
+ *
+ * @returns Pointer to read-only string with the description.
+ * @param rc The status code.
+ */
+#define RTErrGetFull(rc) (RTErrGet(rc)->pszMsgFull)
+
+#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;
+
+/**
+ * Get the message structure corresponding to a given Windows error code.
+ *
+ * @returns Pointer to read-only message description.
+ * @param rc The status code.
+ */
+RTDECL(PCRTWINERRMSG) RTErrWinGet(long rc);
+
+/** On windows COM errors are part of the Windows error database. */
+typedef RTWINERRMSG RTCOMERRMSG;
+
+#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;
+#endif /* !RT_OS_WINDOWS */
+/** 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 /* 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);
+
+/**
+ * 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
+
+/** @} */
+
+/** @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 */
+
+/** @name Misc. Status Codes
+ * @{
+ */
+/** Success. */
+#define VINF_SUCCESS 0
+
+/** 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)
+/** 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
+/** 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)
+/** 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)
+/** @} */
+
+
+/** @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)
+/** @} */
+
+
+/** @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)
+/** @} */
+
+
+/** @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 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)
+/** @} */
+
+
+/** @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)
+/** 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)
+/** @} */
+
+/** @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 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 action (> or |). */
+#define VERR_VFS_CHAIN_EXPECTED_ACTION (-22107)
+/** Only one action element is currently supported. */
+#define VERR_VFS_CHAIN_MULTIPLE_ACTIONS (-22108)
+/** Expected to find a driving action (>), but there is none. */
+#define VERR_VFS_CHAIN_NO_ACTION (-22109)
+/** Expected pipe action. */
+#define VERR_VFS_CHAIN_EXPECTED_PIPE (-22110)
+/** Unexpected action type. */
+#define VERR_VFS_CHAIN_UNEXPECTED_ACTION_TYPE (-22111)
+/** @} */
+
+/** @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)
+/** @} */
+
+/* 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)
+/** @} */
+
+/** @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_IDEFINITE_LENGTH (-22832)
+/** Indefinite length form is not implemented. */
+#define VERR_ASN1_CURSOR_IDEFINITE_LENGTH_NOT_SUP (-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)
+
+/** 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)
+
+/** 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)
+/** @} */
+
+/** @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)
+/** @} */
+
+/** @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)
+/** @} */
+
+/** @name RTCrStore status codes.
+ * @{ */
+/** Generic store error. */
+#define VERR_CR_STORE_GENERIC_ERROR (-23700)
+/** @} */
+
+/** @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)
+/** @} */
+
+/** @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)
+/** @} */
+
+/* SED-END */
+
+/** @} */
+
+#endif
+
--- /dev/null
+/** @file
+ * IPRT - errno.h wrapper.
+ */
+
+/*
+ * Copyright (C) 2012-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+#ifndef ___iprt_errno_h___
+#define ___iprt_errno_h___
+
+#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)
+# 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)
+# 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 (600)
+# 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)
+# else
+# define EINPROGRESS (150)
+# endif
+#endif
+#ifndef ENAMETOOLONG
+# if defined(RT_ERRNO_OS_BSD)
+# define ENAMETOOLONG (63)
+# elif defined(RT_OS_LINUX)
+# define ENAMETOOLONG (36)
+# else
+# define ENAMETOOLONG (78)
+# 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)
+# 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)
+# else
+# define EALREADY (149)
+# endif
+#endif
+
+/** @todo errno constants {37..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)
+# 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
+# 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)
+# 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
--- /dev/null
+/** @file
+ * IPRT - Filesystem.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_fs_h
+#define ___iprt_fs_h
+
+#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,
+
+ /* 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_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_UID if not supported. */
+ RTUID uid;
+
+ /** The group the filesystem object is assigned (st_gid).
+ * This field is NIL_GID 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;
+} 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 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? */
+} 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 DECLCALLBACK(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);
+
+
+#endif /* IN_RING3 */
+
+/** @} */
+
+RT_C_DECLS_END
+
+#endif /* !___iprt_fs_h */
+
--- /dev/null
+/** @file
+ * IPRT - Heap Implementations
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_heap_h
+#define ___iprt_heap_h
+
+#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 DECLCALLBACK(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 DECLCALLBACK(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
+
--- /dev/null
+/** @file
+ * IPRT - Runtime Init/Term.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_initterm_h
+#define ___iprt_initterm_h
+
+#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 (RTR3INIT_XXX).
+ * @{ */
+/** Try initialize SUPLib. */
+#define RTR3INIT_FLAGS_SUPLIB RT_BIT(0)
+/** Initializing IPRT from a DLL. */
+#define RTR3INIT_FLAGS_DLL RT_BIT(1)
+/** We are sharing a process space, so we need to behave. */
+#define RTR3INIT_FLAGS_UNOBTRUSIVE RT_BIT(2)
+/** The caller ensures that the argument bector is UTF-8. */
+#define RTR3INIT_FLAGS_UTF8_ARGV RT_BIT(3)
+/** 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(4)
+/** @} */
+
+/** @name RTR3InitEx version
+ * @{ */
+/** Version 1. */
+#define RTR3INIT_VER_1 UINT32_C(1)
+/** The current version. */
+#define RTR3INIT_VER_CUR RTR3INIT_VER_1
+/** @} */
+
+/**
+ * Initializes the runtime library.
+ *
+ * @returns iprt status code.
+ * @param fFlags Flags, see RTR3INIT_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_XXX.
+ */
+RTR3DECL(int) RTR3InitExe(int cArgs, char ***ppapszArgs, uint32_t fFlags);
+
+/**
+ * Initializes the runtime library.
+ *
+ * @returns iprt status code.
+ * @param fFlags Flags, see RTR3INIT_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_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 DECLCALLBACK(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
+
--- /dev/null
+/** @file
+ * IPRT - String Manipulation, Latin-1 (ISO-8859-1) encoding.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_latin1_h
+#define ___iprt_latin1_h
+
+#include <iprt/string.h>
+
+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
+
--- /dev/null
+/** @file
+ * IPRT - Generic Doubly Linked List.
+ */
+
+/*
+ * Copyright (C) 2010-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_list_h
+#define ___iprt_list_h
+
+#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 */
+#if defined(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;
+
+
+/**
+ * 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);
+ }
+}
+
+/**
+ * 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
--- /dev/null
+/** @file
+ * IPRT - Lock Validator.
+ */
+
+/*
+ * Copyright (C) 2009-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_lockvalidator_h
+#define ___iprt_lockvalidator_h
+
+#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
+
--- /dev/null
+/** @file
+ * IPRT - Logging.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_log_h
+#define ___iprt_log_h
+
+#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_HTTP,
+ RTLOGGROUP_LDR,
+ RTLOGGROUP_PATH,
+ RTLOGGROUP_PROCESS,
+ RTLOGGROUP_SYMLINK,
+ RTLOGGROUP_THREAD,
+ RTLOGGROUP_TIME,
+ RTLOGGROUP_TIMER,
+ RTLOGGROUP_LOCALIPC,
+ 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
+ */
+#define RT_LOGGROUP_NAMES \
+ "DEFAULT", \
+ "RT_CRYPTO", \
+ "RT_DBG", \
+ "RT_DBG_DWARF", \
+ "RT_DIR", \
+ "RT_FILE", \
+ "RT_FS", \
+ "RT_HTTP", \
+ "RT_LDR", \
+ "RT_PATH", \
+ "RT_PROCESS", \
+ "RT_SYMLINK", \
+ "RT_THREAD", \
+ "RT_TIME", \
+ "RT_TIMER", \
+ "RT_LOCALIPC", \
+ "RT_VFS", \
+ "RT_17", \
+ "RT_18", \
+ "RT_19", \
+ "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 you 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. */
+#ifdef IN_RC
+typedef struct RTLOGGERRC RTLOGGER;
+#else
+typedef struct RTLOGGER RTLOGGER;
+#endif
+/** Pointer to logger structure. */
+typedef RTLOGGER *PRTLOGGER;
+/** Pointer to const logger structure. */
+typedef const RTLOGGER *PCRTLOGGER;
+
+
+/** Guest context logger structure. */
+typedef struct RTLOGGERRC RTLOGGERRC;
+/** Pointer to guest context logger structure. */
+typedef RTLOGGERRC *PRTLOGGERRC;
+/** Pointer to const guest context logger structure. */
+typedef const RTLOGGERRC *PCRTLOGGERRC;
+
+
+/**
+ * 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;
+
+
+/**
+ * Logger function.
+ *
+ * @param pszFormat Format string.
+ * @param ... Optional arguments as specified in the format string.
+ */
+typedef DECLCALLBACK(void) FNRTLOGGER(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2);
+/** Pointer to logger function. */
+typedef FNRTLOGGER *PFNRTLOGGER;
+
+/**
+ * Flush function.
+ *
+ * @param pLogger Pointer to the logger instance which is to be flushed.
+ */
+typedef DECLCALLBACK(void) FNRTLOGFLUSH(PRTLOGGER pLogger);
+/** Pointer to flush function. */
+typedef FNRTLOGFLUSH *PFNRTLOGFLUSH;
+
+/**
+ * Flush function.
+ *
+ * @param pLogger Pointer to the logger instance which is to be flushed.
+ */
+typedef DECLCALLBACK(void) FNRTLOGFLUSHGC(PRTLOGGERRC pLogger);
+/** Pointer to logger function. */
+typedef RCPTRTYPE(FNRTLOGFLUSHGC *) PFNRTLOGFLUSHGC;
+
+/**
+ * Header/footer message callback.
+ *
+ * @param pLogger Pointer to the logger instance.
+ * @param pszFormat Format string.
+ * @param ... Optional arguments specified in the format string.
+ */
+typedef DECLCALLBACK(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 DECLCALLBACK(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 DECLCALLBACK(size_t) FNRTLOGPREFIX(PRTLOGGER pLogger, char *pchBuf, size_t cchBuf, void *pvUser);
+/** Pointer to prefix callback function. */
+typedef FNRTLOGPREFIX *PFNRTLOGPREFIX;
+
+
+
+/**
+ * Logger instance structure for raw-mode context (RC).
+ */
+struct RTLOGGERRC
+{
+ /** Pointer to temporary scratch buffer.
+ * This is used to format the log messages. */
+ char achScratch[32768];
+ /** Current scratch buffer position. */
+ uint32_t offScratch;
+ /** This is set if a prefix is pending. */
+ bool fPendingPrefix;
+ bool afAlignment[3];
+ /** Pointer to the logger function.
+ * This is actually pointer to a wrapper 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 C++. */
+ RCPTRTYPE(PFNRTLOGGER) pfnLogger;
+ /** Pointer to the flush function. */
+ PFNRTLOGFLUSHGC pfnFlush;
+ /** Magic number (RTLOGGERRC_MAGIC). */
+ uint32_t u32Magic;
+ /** Logger instance flags - RTLOGFLAGS. */
+ uint32_t fFlags;
+ /** Number of groups in the afGroups member. */
+ uint32_t cGroups;
+ /** Group flags array - RTLOGGRPFLAGS.
+ * This member have variable length and may extend way beyond
+ * the declared size of 1 entry. */
+ uint32_t afGroups[1];
+};
+
+/** RTLOGGERRC::u32Magic value. (John Rogers Searle) */
+#define RTLOGGERRC_MAGIC 0x19320731
+
+
+
+#ifndef IN_RC
+
+/** Pointer to internal logger bits. */
+typedef struct RTLOGGERINTERNAL *PRTLOGGERINTERNAL;
+
+/**
+ * Logger instance structure.
+ */
+struct RTLOGGER
+{
+ /** Pointer to temporary scratch buffer.
+ * This is used to format the log messages. */
+ char achScratch[49152];
+ /** Current scratch buffer position. */
+ uint32_t offScratch;
+ /** Magic number. */
+ uint32_t u32Magic;
+ /** Logger instance flags - RTLOGFLAGS. */
+ uint32_t fFlags;
+ /** Destination flags - RTLOGDEST. */
+ uint32_t fDestFlags;
+ /** Pointer to the internal bits of the logger.
+ * (The memory is allocated in the same block as RTLOGGER.) */
+ PRTLOGGERINTERNAL pInt;
+ /** Pointer to the logger function (used in non-C99 mode only).
+ *
+ * This is actually pointer to a wrapper 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;
+ /** Number of groups in the afGroups and papszGroups members. */
+ uint32_t cGroups;
+ /** Group flags array - RTLOGGRPFLAGS.
+ * This member have variable length and may extend way beyond
+ * the declared size of 1 entry. */
+ uint32_t afGroups[1];
+};
+
+/** RTLOGGER::u32Magic value. (Avram Noam Chomsky) */
+# define RTLOGGER_MAGIC UINT32_C(0x19281207)
+
+#endif /* !IN_RC */
+
+
+/**
+ * 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;
+
+/**
+ * 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 type.
+ */
+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,
+ /** 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;
+
+
+RTDECL(void) RTLogPrintfEx(void *pvInstance, unsigned fFlags, unsigned iGroup,
+ const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(4, 5);
+
+
+#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 enabled 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
+# if defined(RT_ARCH_AMD64) || defined(RT_OS_DARWIN) || defined(RT_ARCH_SPARC) || defined(RT_ARCH_SPARC64)
+# define LOG_USE_C99
+# endif
+#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 \
+ { \
+ register 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 \
+ { \
+ register 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 \
+ { \
+ register 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", __PRETTY_FUNCTION__, _LogRemoveParentheseis a )
+#else
+# define LogWarnFunc(a) \
+ do { LogFlow((LOG_FN_FMT ": ", __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, __PRETTY_FUNCTION__, _LogRemoveParentheseis a )
+#else
+# define LogThisFunc(a) do { Log(("{%p} " LOG_FN_FMT ": ", this, __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, __PRETTY_FUNCTION__, _LogRemoveParentheseis a )
+#else
+# define Log2ThisFunc(a) do { Log2(("{%p} " LOG_FN_FMT ": ", this, __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, __PRETTY_FUNCTION__, _LogRemoveParentheseis a )
+#else
+# define Log3ThisFunc(a) do { Log3(("{%p} " LOG_FN_FMT ": ", this, __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, __PRETTY_FUNCTION__, _LogRemoveParentheseis a )
+#else
+# define Log4ThisFunc(a) do { Log4(("{%p} " LOG_FN_FMT ": ", this, __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, __PRETTY_FUNCTION__, _LogRemoveParentheseis a )
+#else
+# define Log5ThisFunc(a) do { Log5(("{%p} " LOG_FN_FMT ": ", this, __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, __PRETTY_FUNCTION__, _LogRemoveParentheseis a )
+#else
+# define Log6ThisFunc(a) do { Log6(("{%p} " LOG_FN_FMT ": ", this, __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, __PRETTY_FUNCTION__, _LogRemoveParentheseis a )
+#else
+# define Log7ThisFunc(a) do { Log7(("{%p} " LOG_FN_FMT ": ", this, __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, __PRETTY_FUNCTION__, _LogRemoveParentheseis a )
+#else
+# define Log8ThisFunc(a) do { Log8(("{%p} " LOG_FN_FMT ": ", this, __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, __PRETTY_FUNCTION__, _LogRemoveParentheseis a )
+#else
+# define Log9ThisFunc(a) do { Log9(("{%p} " LOG_FN_FMT ": ", this, __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, __PRETTY_FUNCTION__, _LogRemoveParentheseis a )
+#else
+# define Log10ThisFunc(a) do { Log10(("{%p} " LOG_FN_FMT ": ", this, __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, __PRETTY_FUNCTION__, _LogRemoveParentheseis a )
+#else
+# define Log11ThisFunc(a) do { Log11(("{%p} " LOG_FN_FMT ": ", this, __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, __PRETTY_FUNCTION__, _LogRemoveParentheseis a )
+#else
+# define Log12ThisFunc(a) do { Log12(("{%p} " LOG_FN_FMT ": ", this, __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, __PRETTY_FUNCTION__, _LogRemoveParentheseis a )
+#else
+# define LogFlowThisFunc(a) do { LogFlow(("{%p} " LOG_FN_FMT ": ", this, __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, __PRETTY_FUNCTION__, _LogRemoveParentheseis a )
+#else
+# define LogWarnThisFunc(a) do { LogWarn(("{%p} " LOG_FN_FMT ": ", this, __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", __PRETTY_FUNCTION__, _LogRemoveParentheseis a )
+#else
+# define Log1WarningFunc(a) \
+ do { Log((LOG_FN_FMT ": WARNING! ", __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, __PRETTY_FUNCTION__, _LogRemoveParentheseis a )
+#else
+# define Log1WarningThisFunc(a) \
+ do { Log(("{%p} " LOG_FN_FMT ": WARNING! ", this, __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__, __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
+/** @} */
+
+
+
+/** @name 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) ( RTLogRelGetDefaultInstanceEx(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 = RTLogRelGetDefaultInstanceEx(RT_MAKE_U32(a_fFlags, a_iGroup)); \
+ if (RT_LIKELY(!LogRelIt_pLogger)) \
+ { /* likely */ } \
+ else \
+ RTLogLoggerEx(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 = RTLogRelGetDefaultInstanceEx(RT_MAKE_U32(a_fFlags, a_iGroup)); \
+ if (LogRelIt_pLogger) \
+ RTLogLoggerEx(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 = RTLogRelGetDefaultInstanceEx(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++; \
+ RTLogLoggerEx(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 = RTLogRelGetDefaultInstanceEx(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 = RTLogRelGetDefaultInstanceEx(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 = RTLogRelGetDefaultInstanceEx(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", __PRETTY_FUNCTION__, _LogRemoveParentheseis a )
+#else
+# define LogRelFlowFunc(a) do { LogRelFlow((LOG_FN_FMT ": ", __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", __PRETTY_FUNCTION__, _LogRemoveParentheseis a )
+#else
+# define LogRelMaxFunc(a_cMax, a) \
+ do { LogRelMax(a_cMax, (LOG_FN_FMT ": ", __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", __PRETTY_FUNCTION__, _LogRemoveParentheseis a )
+#else
+# define LogRelMaxFlowFunc(a_cMax, a) \
+ do { LogRelMaxFlow(a_cMax, (LOG_FN_FMT ": ", __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, __PRETTY_FUNCTION__, _LogRemoveParentheseis a )
+#else
+# define LogRelThisFunc(a) \
+ do { LogRel(("{%p} " LOG_FN_FMT ": ", this, __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, __PRETTY_FUNCTION__, _LogRemoveParentheseis a )
+#else
+# define LogRelMaxThisFunc(a_cMax, a) \
+ do { LogRelMax(a_cMax, ("{%p} " LOG_FN_FMT ": ", this, __PRETTY_FUNCTION__)); LogRelMax(a_cMax, a); } while (0)
+#endif
+
+/** @} */
+
+
+#ifndef IN_RC
+/**
+ * Sets the default release logger instance.
+ *
+ * @returns The old default instance.
+ * @param pLogger The new default release logger instance.
+ */
+RTDECL(PRTLOGGER) RTLogRelSetDefaultInstance(PRTLOGGER pLogger);
+#endif /* !IN_RC */
+
+/**
+ * Gets the default release logger instance.
+ *
+ * @returns Pointer to default release logger instance if availble, otherwise NULL.
+ */
+RTDECL(PRTLOGGER) RTLogRelGetDefaultInstance(void);
+
+/**
+ * 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);
+
+/**
+ * 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.
+ *
+ * @returns Pointer to default logger instance if availble, otherwise NULL.
+ */
+RTDECL(PRTLOGGER) RTLogGetDefaultInstance(void);
+
+/**
+ * Gets the default logger instance if enabled.
+ *
+ * @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);
+
+#ifndef IN_RC
+/**
+ * Sets the default logger instance.
+ *
+ * @returns The old default instance.
+ * @param pLogger The new default logger instance.
+ */
+RTDECL(PRTLOGGER) RTLogSetDefaultInstance(PRTLOGGER pLogger);
+#endif /* !IN_RC */
+
+#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.
+ */
+RTDECL(int) RTLogSetDefaultInstanceThread(PRTLOGGER pLogger, uintptr_t uKey);
+#endif /* IN_RING0 */
+
+
+#ifndef IN_RC
+/**
+ * Creates the default logger instance for a 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);
+
+/**
+ * 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, uint32_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 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 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 pszErrorMsg A buffer which is filled with an error message if something fails. May be NULL.
+ * @param cchErrorMsg The size of the error message buffer.
+ * @param pszFilenameFmt Log filename format string. Standard RTStrFormat().
+ * @param ... Format arguments.
+ */
+RTDECL(int) RTLogCreateEx(PRTLOGGER *ppLogger, uint32_t fFlags, const char *pszGroupSettings,
+ const char *pszEnvVarBase, unsigned cGroups, const char * const * papszGroups,
+ uint32_t fDestFlags, PFNRTLOGPHASE pfnPhase, uint32_t cHistory,
+ uint64_t cbHistoryFileMax, uint32_t cSecsHistoryTimeSlot, char *pszErrorMsg, size_t cchErrorMsg,
+ const char *pszFilenameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(14, 15);
+
+/**
+ * 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 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 pszErrorMsg A buffer which is filled with an error message
+ * if something fails. May be NULL.
+ * @param cchErrorMsg The size of the error message buffer.
+ * @param pszFilenameFmt Log filename format string. Standard
+ * RTStrFormat().
+ * @param args Format arguments.
+ */
+RTDECL(int) RTLogCreateExV(PRTLOGGER *ppLogger, uint32_t fFlags, const char *pszGroupSettings,
+ const char *pszEnvVarBase, unsigned cGroups, const char * const * papszGroups,
+ uint32_t fDestFlags, PFNRTLOGPHASE pfnPhase, uint32_t cHistory,
+ uint64_t cbHistoryFileMax, uint32_t cSecsHistoryTimeSlot, char *pszErrorMsg, size_t cchErrorMsg,
+ const char *pszFilenameFmt, va_list args) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(14, 0);
+
+/**
+ * Create a logger instance for singled threaded ring-0 usage.
+ *
+ * @returns iprt status code.
+ *
+ * @param pLogger Where to create the logger instance.
+ * @param cbLogger The amount of memory available for the logger instance.
+ * @param pLoggerR0Ptr The ring-0 address corresponding to @a pLogger.
+ * @param pfnLoggerR0Ptr Pointer to logger wrapper function.
+ * @param pfnFlushR0Ptr Pointer to flush function.
+ * @param fFlags Logger instance flags, a combination of the RTLOGFLAGS_* values.
+ * @param fDestFlags The destination flags.
+ */
+RTDECL(int) RTLogCreateForR0(PRTLOGGER pLogger, size_t cbLogger,
+ RTR0PTR pLoggerR0Ptr, RTR0PTR pfnLoggerR0Ptr, RTR0PTR pfnFlushR0Ptr,
+ uint32_t fFlags, uint32_t fDestFlags);
+
+/**
+ * Calculates the minimum size of a ring-0 logger instance.
+ *
+ * @returns The minimum size.
+ * @param cGroups The number of groups.
+ * @param fFlags Relevant flags.
+ */
+RTDECL(size_t) RTLogCalcSizeForR0(uint32_t cGroups, uint32_t fFlags);
+
+/**
+ * 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);
+
+/**
+ * Create a logger instance clone for RC usage.
+ *
+ * @returns iprt status code.
+ *
+ * @param pLogger The logger instance to be cloned.
+ * @param pLoggerRC Where to create the RC logger instance.
+ * @param cbLoggerRC Amount of memory allocated to for the RC logger
+ * instance clone.
+ * @param pfnLoggerRCPtr Pointer to logger wrapper function for this
+ * instance (RC Ptr).
+ * @param pfnFlushRCPtr Pointer to flush function (RC Ptr).
+ * @param fFlags Logger instance flags, a combination of the RTLOGFLAGS_* values.
+ */
+RTDECL(int) RTLogCloneRC(PRTLOGGER pLogger, PRTLOGGERRC pLoggerRC, size_t cbLoggerRC,
+ RTRCPTR pfnLoggerRCPtr, RTRCPTR pfnFlushRCPtr, uint32_t fFlags);
+
+/**
+ * Flushes a RC logger instance to a R3 logger.
+ *
+ * @returns iprt status code.
+ * @param pLogger The R3 logger instance to flush pLoggerRC to. If NULL
+ * the default logger is used.
+ * @param pLoggerRC The RC logger instance to flush.
+ */
+RTDECL(void) RTLogFlushRC(PRTLOGGER pLogger, PRTLOGGERRC pLoggerRC);
+
+/**
+ * Flushes the buffer in one logger instance onto another logger.
+ *
+ * @returns iprt status code.
+ *
+ * @param pSrcLogger The logger instance to flush.
+ * @param pDstLogger The logger instance to flush onto.
+ * If NULL the default logger will be used.
+ */
+RTDECL(void) RTLogFlushToLogger(PRTLOGGER pSrcLogger, PRTLOGGER pDstLogger);
+
+/**
+ * Flushes a R0 logger instance to a R3 logger.
+ *
+ * @returns iprt status code.
+ * @param pLogger The R3 logger instance to flush pLoggerR0 to. If NULL
+ * the default logger is used.
+ * @param pLoggerR0 The R0 logger instance to flush.
+ */
+RTDECL(void) RTLogFlushR0(PRTLOGGER pLogger, PRTLOGGER pLoggerR0);
+
+/**
+ * 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);
+
+/**
+ * Same as RTLogSetCustomPrefixCallback for loggers created by
+ * RTLogCreateForR0.
+ *
+ * @returns IPRT status code.
+ * @param pLogger The logger instance.
+ * @param pLoggerR0Ptr The ring-0 address corresponding to @a pLogger.
+ * @param pfnCallbackR0Ptr The callback.
+ * @param pvUserR0Ptr The user argument for the callback.
+ * */
+RTDECL(int) RTLogSetCustomPrefixCallbackForR0(PRTLOGGER pLogger, RTR0PTR pLoggerR0Ptr,
+ RTR0PTR pfnCallbackR0Ptr, RTR0PTR pvUserR0Ptr);
+
+/**
+ * Copies the group settings and flags from logger instance to another.
+ *
+ * @returns IPRT status code.
+ * @param pDstLogger The destination logger instance.
+ * @param pDstLoggerR0Ptr The ring-0 address corresponding to @a pDstLogger.
+ * @param pSrcLogger The source logger instance. If NULL the default one is used.
+ * @param fFlagsOr OR mask for the flags.
+ * @param fFlagsAnd AND mask for the flags.
+ */
+RTDECL(int) RTLogCopyGroupsAndFlagsForR0(PRTLOGGER pDstLogger, RTR0PTR pDstLoggerR0Ptr,
+ PCRTLOGGER pSrcLogger, uint32_t fFlagsOr, uint32_t fFlagsAnd);
+
+/**
+ * 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) RTLogGetGroupSettings(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);
+#endif /* !IN_RC */
+
+/**
+ * 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);
+
+/**
+ * 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);
+
+#ifndef IN_RC
+/**
+ * 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) RTLogGetFlags(PRTLOGGER pLogger, char *pszBuf, size_t cchBuf);
+
+/**
+ * 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);
+
+/**
+ * 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) RTLogGetDestinations(PRTLOGGER pLogger, char *pszBuf, size_t cchBuf);
+#endif /* !IN_RC */
+
+/**
+ * Flushes the specified logger.
+ *
+ * @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(void) 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.
+ *
+ * @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(3, 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.
+ *
+ * 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 args Format arguments.
+ */
+RTDECL(void) RTLogLoggerExV(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 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);
+
+
+#ifndef DECLARED_FNRTSTROUTPUT /* duplicated in iprt/string.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 DECLCALLBACK(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);
+
+
+#if 0 /* not implemented yet */
+
+/** Indicates that the semaphores shall be used to notify the other
+ * part about buffer changes. */
+#define LOGHOOKBUFFER_FLAGS_SEMAPHORED 1
+
+/**
+ * Log Hook Buffer.
+ * Use to communicate between the logger and a log consumer.
+ */
+typedef struct RTLOGHOOKBUFFER
+{
+ /** Write pointer. */
+ volatile void *pvWrite;
+ /** Read pointer. */
+ volatile void *pvRead;
+ /** Buffer start. */
+ void *pvStart;
+ /** Buffer end (exclusive). */
+ void *pvEnd;
+ /** Signaling semaphore used by the writer to wait on a full buffer.
+ * Only used when indicated in flags. */
+ void *pvSemWriter;
+ /** Signaling semaphore used by the read to wait on an empty buffer.
+ * Only used when indicated in flags. */
+ void *pvSemReader;
+ /** Buffer flags. Current reserved and set to zero. */
+ volatile unsigned fFlags;
+} RTLOGHOOKBUFFER;
+/** Pointer to a log hook buffer. */
+typedef RTLOGHOOKBUFFER *PRTLOGHOOKBUFFER;
+
+
+/**
+ * Register a logging hook.
+ *
+ * This type of logging hooks are expecting different threads acting
+ * producer and consumer. They share a circular buffer which have two
+ * pointers one for each end. When the buffer is full there are two
+ * alternatives (indicated by a buffer flag), either wait for the
+ * consumer to get it's job done, or to write a generic message saying
+ * buffer overflow.
+ *
+ * Since the waiting would need a signal semaphore, we'll skip that for now.
+ *
+ * @returns iprt status code.
+ * @param pBuffer Pointer to a logger hook buffer.
+ */
+RTDECL(int) RTLogRegisterHook(PRTLOGGER pLogger, PRTLOGHOOKBUFFER pBuffer);
+
+/**
+ * Deregister a logging hook registered with RTLogRegisterHook().
+ *
+ * @returns iprt status code.
+ * @param pBuffer Pointer to a logger hook buffer.
+ */
+RTDECL(int) RTLogDeregisterHook(PRTLOGGER pLogger, PRTLOGHOOKBUFFER pBuffer);
+
+#endif /* not implemented yet */
+
+
+
+/**
+ * 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 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
+
--- /dev/null
+/** @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-2017 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_mangling_h
+#define ___iprt_mangling_h
+
+#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 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 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 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 RTBase64Encode RT_MANGLER(RTBase64Encode)
+# define RTBase64EncodedLength RT_MANGLER(RTBase64EncodedLength)
+# 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 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 RTDbgCfgOpenDbg RT_MANGLER(RTDbgCfgOpenDbg)
+# define RTDbgCfgOpenDsymBundle RT_MANGLER(RTDbgCfgOpenDsymBundle)
+# define RTDbgCfgOpenMachOImage RT_MANGLER(RTDbgCfgOpenMachOImage)
+# define RTDbgCfgOpenDwo RT_MANGLER(RTDbgCfgOpenDwo)
+# 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 RTDbgModImageSize RT_MANGLER(RTDbgModImageSize)
+# 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 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 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 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 RTDirRemove RT_MANGLER(RTDirRemove)
+# define RTDirRemoveRecursive RT_MANGLER(RTDirRemoveRecursive)
+# define RTDirRename RT_MANGLER(RTDirRename)
+# define RTDirSetTimes RT_MANGLER(RTDirSetTimes)
+# define RTDvmCreate RT_MANGLER(RTDvmCreate)
+# define RTDvmRetain RT_MANGLER(RTDvmRetain)
+# define RTDvmRelease RT_MANGLER(RTDvmRelease)
+# define RTDvmMapOpen RT_MANGLER(RTDvmMapOpen)
+# define RTDvmMapInitialize RT_MANGLER(RTDvmMapInitialize)
+# define RTDvmMapGetFormat RT_MANGLER(RTDvmMapGetFormat)
+# 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 RTDvmVolumeRetain RT_MANGLER(RTDvmVolumeRetain)
+# define RTDvmVolumeRelease RT_MANGLER(RTDvmVolumeRelease)
+# define RTDvmVolumeGetSize RT_MANGLER(RTDvmVolumeGetSize)
+# define RTDvmVolumeQueryName RT_MANGLER(RTDvmVolumeQueryName)
+# define RTDvmVolumeGetType RT_MANGLER(RTDvmVolumeGetType)
+# define RTDvmVolumeGetFlags RT_MANGLER(RTDvmVolumeGetFlags)
+# 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 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 RTEnvCreateChangeRecord RT_MANGLER(RTEnvCreateChangeRecord)
+# define RTEnvDestroy RT_MANGLER(RTEnvDestroy)
+# 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 RTErrGet RT_MANGLER(RTErrGet)
+# 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 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 RTFileCopyByHandles RT_MANGLER(RTFileCopyByHandles)
+# define RTFileCopyByHandlesEx RT_MANGLER(RTFileCopyByHandlesEx)
+# define RTFileCopyEx RT_MANGLER(RTFileCopyEx)
+# define RTFileCreateTemp RT_MANGLER(RTFileCreateTemp)
+# define RTFileCreateTempSecure RT_MANGLER(RTFileCreateTempSecure)
+# define RTFileDelete RT_MANGLER(RTFileDelete)
+# define RTFileExists RT_MANGLER(RTFileExists)
+# define RTFileFlush RT_MANGLER(RTFileFlush)
+# define RTFileFromNative RT_MANGLER(RTFileFromNative)
+# define RTFileGetMaxSize RT_MANGLER(RTFileGetMaxSize)
+# define RTFileGetMaxSizeEx RT_MANGLER(RTFileGetMaxSizeEx)
+# define RTFileGetSize RT_MANGLER(RTFileGetSize)
+# 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 RTFileOpenF RT_MANGLER(RTFileOpenF)
+# define RTFileOpenV RT_MANGLER(RTFileOpenV)
+# define RTFileOpenTemp RT_MANGLER(RTFileOpenTemp)
+# define RTFileQueryFsSizes RT_MANGLER(RTFileQueryFsSizes)
+# define RTFileQueryInfo RT_MANGLER(RTFileQueryInfo)
+# define RTFileQuerySize RT_MANGLER(RTFileQuerySize)
+# 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 RTFileSgReadAt RT_MANGLER(RTFileSgReadAt)
+# 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 RTGetOpt RT_MANGLER(RTGetOpt)
+# define RTGetOptArgvFree RT_MANGLER(RTGetOptArgvFree)
+# 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 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 RTHttpUseSystemProxySettings RT_MANGLER(RTHttpUseSystemProxySettings)
+# define RTIsoFsClose RT_MANGLER(RTIsoFsClose)
+# define RTIsoFsExtractFile RT_MANGLER(RTIsoFsExtractFile)
+# define RTIsoFsGetFileInfo RT_MANGLER(RTIsoFsGetFileInfo)
+# define RTIsoFsOpen RT_MANGLER(RTIsoFsOpen)
+# define RTJsonIteratorBegin RT_MANGLER(RTJsonIteratorBegin)
+# 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 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 RTJsonValueQueryString RT_MANGLER(RTJsonValueQueryString)
+# define RTJsonValueQueryStringByName RT_MANGLER(RTJsonValueQueryStringByName)
+# define RTJsonValueRelease RT_MANGLER(RTJsonValueRelease)
+# define RTJsonValueRetain RT_MANGLER(RTJsonValueRetain)
+# 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 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 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 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 RTLdrOpen RT_MANGLER(RTLdrOpen)
+# define RTLdrOpenEx RT_MANGLER(RTLdrOpenEx)
+# define RTLdrOpenInMemory RT_MANGLER(RTLdrOpenInMemory)
+# define RTLdrOpenkLdr RT_MANGLER(RTLdrOpenkLdr)
+# 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 RTLinuxCheckDevicePath RT_MANGLER(RTLinuxCheckDevicePath)
+# define RTLinuxCheckDevicePathV RT_MANGLER(RTLinuxCheckDevicePathV)
+# 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 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 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 RTLogBackdoorPrintf RT_MANGLER(RTLogBackdoorPrintf) /* r0drv-guest */
+# define RTLogBackdoorPrintfV RT_MANGLER(RTLogBackdoorPrintfV) /* r0drv-guest */
+# define RTLogCalcSizeForR0 RT_MANGLER(RTLogCalcSizeForR0)
+# define RTLogCloneRC RT_MANGLER(RTLogCloneRC)
+# define RTLogComPrintf RT_MANGLER(RTLogComPrintf)
+# define RTLogComPrintfV RT_MANGLER(RTLogComPrintfV)
+# define RTLogCopyGroupsAndFlagsForR0 RT_MANGLER(RTLogCopyGroupsAndFlagsForR0)
+# define RTLogCreate RT_MANGLER(RTLogCreate)
+# define RTLogCreateEx RT_MANGLER(RTLogCreateEx)
+# define RTLogCreateExV RT_MANGLER(RTLogCreateExV)
+# define RTLogCreateForR0 RT_MANGLER(RTLogCreateForR0)
+# 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 RTLogFlushRC RT_MANGLER(RTLogFlushRC)
+# define RTLogFlushR0 RT_MANGLER(RTLogFlushR0)
+# define RTLogFlushToLogger RT_MANGLER(RTLogFlushToLogger)
+# 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 RTLogGetGroupSettings RT_MANGLER(RTLogGetGroupSettings)
+# define RTLogGroupSettings RT_MANGLER(RTLogGroupSettings)
+# define RTLogLogger RT_MANGLER(RTLogLogger)
+# define RTLogLoggerEx RT_MANGLER(RTLogLoggerEx)
+# 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 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 RTLogSetCustomPrefixCallbackForR0 RT_MANGLER(RTLogSetCustomPrefixCallbackForR0)
+# define RTLogSetDefaultInstance RT_MANGLER(RTLogSetDefaultInstance)
+# define RTLogSetDefaultInstanceThread RT_MANGLER(RTLogSetDefaultInstanceThread) /* r0drv */
+# define RTLogSetGroupLimit RT_MANGLER(RTLogSetGroupLimit)
+# define RTLogWriteCom RT_MANGLER(RTLogWriteCom)
+# 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 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 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 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 RTMemEfRealloc RT_MANGLER(RTMemEfRealloc)
+# define RTMemEfReallocNP RT_MANGLER(RTMemEfReallocNP)
+# 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 RTMemExecAllocTag RT_MANGLER(RTMemExecAllocTag)
+# define RTMemExecFree RT_MANGLER(RTMemExecFree)
+# define RTMemFree RT_MANGLER(RTMemFree)
+# define RTMemFreeEx RT_MANGLER(RTMemFreeEx)
+# define RTMemLockedAllocExTag RT_MANGLER(RTMemLockedAllocExTag)
+# define RTMemLockedAllocZExTag RT_MANGLER(RTMemLockedAllocZExTag)
+# define RTMemLockedAllocTag RT_MANGLER(RTMemLockedAllocTag)
+# define RTMemLockedAllocZTag RT_MANGLER(RTMemLockedAllocZTag)
+# define RTMemLockedFree RT_MANGLER(RTMemLockedFree)
+# define RTMemPageAllocTag RT_MANGLER(RTMemPageAllocTag)
+# 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 RTMemTmpAllocTag RT_MANGLER(RTMemTmpAllocTag)
+# define RTMemTmpAllocZTag RT_MANGLER(RTMemTmpAllocZTag)
+# define RTMemTmpFree RT_MANGLER(RTMemTmpFree)
+# 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 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 RTMsgWarning RT_MANGLER(RTMsgWarning)
+# define RTMsgWarningV RT_MANGLER(RTMsgWarningV)
+# 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 RTNetMaskToPrefixIPv4 RT_MANGLER(RTNetMaskToPrefixIPv4)
+# define RTNetPrefixToMaskIPv4 RT_MANGLER(RTNetPrefixToMaskIPv4)
+# define RTNetTCPChecksum RT_MANGLER(RTNetTCPChecksum)
+# define RTNetUDPChecksum RT_MANGLER(RTNetUDPChecksum)
+# define RTNetStrToMacAddr RT_MANGLER(RTNetStrToMacAddr)
+# define RTNetIsIPv4AddrStr RT_MANGLER(RTNetIsIPv4AddrStr)
+# define RTNetStrIsIPv4AddrAny RT_MANGLER(RTNetStrIsIPv4AddrAny)
+# define RTNetStrToIPv4AddrEx RT_MANGLER(RTNetStrToIPv4AddrEx)
+# define RTNetStrToIPv4Addr RT_MANGLER(RTNetStrToIPv4Addr)
+# define RTNetIsIPv6AddrStr RT_MANGLER(RTNetIsIPv6AddrStr)
+# define RTNetStrIsIPv6AddrAny RT_MANGLER(RTNetStrIsIPv6AddrAny)
+# define RTNetStrToIPv6AddrEx RT_MANGLER(RTNetStrToIPv6AddrEx)
+# define RTNetStrToIPv6Addr RT_MANGLER(RTNetStrToIPv6Addr)
+# define RTNetMaskToPrefixIPv6 RT_MANGLER(RTNetMaskToPrefixIPv6)
+# define RTNetPrefixToMaskIPv6 RT_MANGLER(RTNetPrefixToMaskIPv6)
+# 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 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 RTPathFilenameEx RT_MANGLER(RTPathFilenameEx)
+# define RTPathGetCurrent RT_MANGLER(RTPathGetCurrent)
+# define RTPathGetCurrentDrive RT_MANGLER(RTPathGetCurrentDrive)
+# define RTPathGetCurrentOnDrive RT_MANGLER(RTPathGetCurrentOnDrive)
+# define RTPathGetMode RT_MANGLER(RTPathGetMode)
+# define 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 RTPathParse RT_MANGLER(RTPathParse)
+# define RTPathParsedReassemble RT_MANGLER(RTPathParsedReassemble)
+# define RTPathParseSimple RT_MANGLER(RTPathParseSimple)
+# 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 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 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 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 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 RTR0DbgKrnlInfoRelease RT_MANGLER(RTR0DbgKrnlInfoRelease) /* r0drv */
+# define RTR0DbgKrnlInfoRetain RT_MANGLER(RTR0DbgKrnlInfoRetain) /* r0drv */
+# define RTR0Init RT_MANGLER(RTR0Init) /* r0drv */
+# define RTR0MemAreKrnlAndUsrDifferent RT_MANGLER(RTR0MemAreKrnlAndUsrDifferent) /* r0drv */
+# define RTR0MemExecDonate RT_MANGLER(RTR0MemExecDonate) /* 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 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 RTR0MemObjProtect RT_MANGLER(RTR0MemObjProtect) /* r0drv */
+# define RTR0MemObjReserveKernelTag RT_MANGLER(RTR0MemObjReserveKernelTag) /* r0drv */
+# define RTR0MemObjReserveUserTag RT_MANGLER(RTR0MemObjReserveUserTag) /* r0drv */
+# define RTR0MemObjSize RT_MANGLER(RTR0MemObjSize) /* r0drv */
+# define RTR0MemUserCopyFrom RT_MANGLER(RTR0MemUserCopyFrom) /* r0drv */
+# define RTR0MemUserCopyTo RT_MANGLER(RTR0MemUserCopyTo) /* r0drv */
+# define RTR0MemUserIsValidAddr RT_MANGLER(RTR0MemUserIsValidAddr) /* r0drv */
+# 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 RTReqSubmit RT_MANGLER(RTReqSubmit)
+# define RTReqRelease RT_MANGLER(RTReqRelease)
+# define RTReqRetain RT_MANGLER(RTReqRetain)
+# 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 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 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 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 RTSgBufCopyToBuf RT_MANGLER(RTSgBufCopyToBuf)
+# 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 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 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 RTStrDupExTag RT_MANGLER(RTStrDupExTag)
+# define RTStrDupNTag RT_MANGLER(RTStrDupNTag)
+# define RTStrDupTag RT_MANGLER(RTStrDupTag)
+# define RTStrFormat RT_MANGLER(RTStrFormat)
+# define RTStrFormatNumber RT_MANGLER(RTStrFormatNumber)
+# 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 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 RTStrmInputGetEchoChars RT_MANGLER(RTStrmInputGetEchoChars)
+# define RTStrmGetLine RT_MANGLER(RTStrmGetLine)
+# define RTStrmOpen RT_MANGLER(RTStrmOpen)
+# define RTStrmOpenF RT_MANGLER(RTStrmOpenF)
+# define RTStrmOpenFV RT_MANGLER(RTStrmOpenFV)
+# define RTStrmPrintf RT_MANGLER(RTStrmPrintf)
+# define RTStrmPrintfV RT_MANGLER(RTStrmPrintfV)
+# 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 RTStrmInputSetEchoChars RT_MANGLER(RTStrmInputSetEchoChars)
+# define RTStrmSetMode RT_MANGLER(RTStrmSetMode)
+# define RTStrmWriteEx RT_MANGLER(RTStrmWriteEx)
+# define RTStrNCmp RT_MANGLER(RTStrNCmp)
+# define RTStrNICmp RT_MANGLER(RTStrNICmp)
+# 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 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 RTStrToUni RT_MANGLER(RTStrToUni)
+# define RTStrToUniEx RT_MANGLER(RTStrToUniEx)
+# define RTStrToUpper RT_MANGLER(RTStrToUpper)
+# 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 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 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 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 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 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 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 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 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 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 RTTimeDbgBad RT_MANGLER(RTTimeDbgBad)
+# define RTTimeDbgExpired RT_MANGLER(RTTimeDbgExpired)
+# define RTTimeDbgRaces RT_MANGLER(RTTimeDbgRaces)
+# define RTTimeDbgSteps RT_MANGLER(RTTimeDbgSteps)
+# define RTTimeExplode RT_MANGLER(RTTimeExplode)
+# define RTTimeImplode RT_MANGLER(RTTimeImplode)
+# define RTTimeIsLeapYear RT_MANGLER(RTTimeIsLeapYear)
+# define RTTimeLocalDeltaNano RT_MANGLER(RTTimeLocalDeltaNano)
+# define RTTimeLocalExplode RT_MANGLER(RTTimeLocalExplode)
+# 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 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 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 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 RTTimeNanoTSLFenceSyncInvarWithDeltaUseRdtscp RT_MANGLER(RTTimeNanoTSLFenceSyncInvarWithDeltaUseRdtscp)
+# define RTTimeNanoTSLFenceSyncInvarWithDeltaUseRdtscp_EndProc RT_MANGLER(RTTimeNanoTSLFenceSyncInvarWithDeltaUseRdtscp_EndProc)
+# define RTTimeNanoTSLFenceSyncInvarWithDeltaUseIdtrLim RT_MANGLER(RTTimeNanoTSLFenceSyncInvarWithDeltaUseIdtrLim)
+# define RTTimeNanoTSLFenceSyncInvarWithDeltaUseIdtrLim_EndProc RT_MANGLER(RTTimeNanoTSLFenceSyncInvarWithDeltaUseIdtrLim_EndProc)
+# 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 RTTimeToString RT_MANGLER(RTTimeToString)
+# 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 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 RTTraceSetDefaultBuf RT_MANGLER(RTTraceSetDefaultBuf)
+# define RTUdpCreateClientSocket RT_MANGLER(RTUdpCreateClientSocket)
+# 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 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 RTUtf16GetCpInternal RT_MANGLER(RTUtf16GetCpInternal)
+# define RTUtf16ICmp RT_MANGLER(RTUtf16ICmp)
+# define RTUtf16ICmpUtf8 RT_MANGLER(RTUtf16ICmpUtf8)
+# define RTUtf16IsValidEncoding RT_MANGLER(RTUtf16IsValidEncoding)
+# define RTUtf16Len RT_MANGLER(RTUtf16Len)
+# define RTUtf16LocaleICmp RT_MANGLER(RTUtf16LocaleICmp)
+# define RTUtf16PutCpInternal RT_MANGLER(RTUtf16PutCpInternal)
+# 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 RTUtf16ToUtf8Tag RT_MANGLER(RTUtf16ToUtf8Tag)
+# define RTUtf16ValidateEncoding RT_MANGLER(RTUtf16ValidateEncoding)
+# define RTUtf16ValidateEncodingEx RT_MANGLER(RTUtf16ValidateEncodingEx)
+# 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 RTVfsChainOpenFile RT_MANGLER(RTVfsChainOpenFile)
+# define RTVfsChainOpenIoStream RT_MANGLER(RTVfsChainOpenIoStream)
+# define RTVfsChainSpecFree RT_MANGLER(RTVfsChainSpecFree)
+# define RTVfsChainSpecParse RT_MANGLER(RTVfsChainSpecParse)
+# define RTVfsDirRelease RT_MANGLER(RTVfsDirRelease)
+# define RTVfsDirRetain RT_MANGLER(RTVfsDirRetain)
+# define RTVfsFileFlush RT_MANGLER(RTVfsFileFlush)
+# define RTVfsFileFromBuffer RT_MANGLER(RTVfsFileFromBuffer)
+# define RTVfsFileFromRTFile RT_MANGLER(RTVfsFileFromRTFile)
+# define RTVfsFileGetSize RT_MANGLER(RTVfsFileGetSize)
+# define RTVfsFileOpen RT_MANGLER(RTVfsFileOpen)
+# define RTVfsFileOpenNormal RT_MANGLER(RTVfsFileOpenNormal)
+# define RTVfsFilePoll RT_MANGLER(RTVfsFilePoll)
+# define RTVfsFileQueryInfo RT_MANGLER(RTVfsFileQueryInfo)
+# define RTVfsFileRead RT_MANGLER(RTVfsFileRead)
+# define RTVfsFileReadAt RT_MANGLER(RTVfsFileReadAt)
+# define RTVfsFileRelease RT_MANGLER(RTVfsFileRelease)
+# define RTVfsFileRetain RT_MANGLER(RTVfsFileRetain)
+# define RTVfsFileSeek RT_MANGLER(RTVfsFileSeek)
+# define RTVfsFileTell RT_MANGLER(RTVfsFileTell)
+# define RTVfsFileToIoStream RT_MANGLER(RTVfsFileToIoStream)
+# define RTVfsFileWrite RT_MANGLER(RTVfsFileWrite)
+# define RTVfsFileWriteAt RT_MANGLER(RTVfsFileWriteAt)
+# define RTVfsFsStrmNext RT_MANGLER(RTVfsFsStrmNext)
+# define RTVfsFsStrmQueryInfo RT_MANGLER(RTVfsFsStrmQueryInfo)
+# define RTVfsFsStrmRelease RT_MANGLER(RTVfsFsStrmRelease)
+# define RTVfsFsStrmRetain RT_MANGLER(RTVfsFsStrmRetain)
+# 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 RTVfsIoStrmIsAtEnd RT_MANGLER(RTVfsIoStrmIsAtEnd)
+# define RTVfsIoStrmOpenNormal RT_MANGLER(RTVfsIoStrmOpenNormal)
+# define RTVfsIoStrmPoll RT_MANGLER(RTVfsIoStrmPoll)
+# 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 RTVfsIoStrmSgRead RT_MANGLER(RTVfsIoStrmSgRead)
+# define RTVfsIoStrmSgWrite RT_MANGLER(RTVfsIoStrmSgWrite)
+# define RTVfsIoStrmSkip RT_MANGLER(RTVfsIoStrmSkip)
+# 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 RTVfsIsRangeInUse RT_MANGLER(RTVfsIsRangeInUse)
+# 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 RTVfsMemFileCreate RT_MANGLER(RTVfsMemFileCreate)
+# define RTVfsMemorizeIoStreamAsFile RT_MANGLER(RTVfsMemorizeIoStreamAsFile)
+# define RTVfsNew RT_MANGLER(RTVfsNew)
+# define RTVfsNewBaseObj RT_MANGLER(RTVfsNewBaseObj)
+# 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 RTVfsObjQueryInfo RT_MANGLER(RTVfsObjQueryInfo)
+# define RTVfsObjRelease RT_MANGLER(RTVfsObjRelease)
+# define RTVfsObjRetain RT_MANGLER(RTVfsObjRetain)
+# define RTVfsObjToDir RT_MANGLER(RTVfsObjToDir)
+# define RTVfsObjToFile RT_MANGLER(RTVfsObjToFile)
+# define RTVfsObjToFsStream RT_MANGLER(RTVfsObjToFsStream)
+# define RTVfsObjToIoStream RT_MANGLER(RTVfsObjToIoStream)
+# 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 RTVfsRetain RT_MANGLER(RTVfsRetain)
+# define RTVfsSymlinkQueryInfo RT_MANGLER(RTVfsSymlinkQueryInfo)
+# define RTVfsSymlinkRead RT_MANGLER(RTVfsSymlinkRead)
+# define RTVfsSymlinkRelease RT_MANGLER(RTVfsSymlinkRelease)
+# define RTVfsSymlinkRetain RT_MANGLER(RTVfsSymlinkRetain)
+# define RTVfsSymlinkSetMode RT_MANGLER(RTVfsSymlinkSetMode)
+# define RTVfsSymlinkSetOwner RT_MANGLER(RTVfsSymlinkSetOwner)
+# define RTVfsSymlinkSetTimes RT_MANGLER(RTVfsSymlinkSetTimes)
+# define RTVfsUtilDummyPollOne RT_MANGLER(RTVfsUtilDummyPollOne)
+# define RTVfsUtilPumpIoStreams RT_MANGLER(RTVfsUtilPumpIoStreams)
+# 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 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 RTZipXarFsStreamFromIoStream RT_MANGLER(RTZipXarFsStreamFromIoStream)
+
+/* 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 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 RTAsn1CursorInitSubFromCore RT_MANGLER(RTAsn1CursorInitSubFromCore)
+# define RTAsn1CursorIsNextEx RT_MANGLER(RTAsn1CursorIsNextEx)
+# 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 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 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_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_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_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 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_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 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 RTCrDigestClone RT_MANGLER(RTCrDigestClone)
+# define RTCrDigestCreate RT_MANGLER(RTCrDigestCreate)
+# define RTCrDigestFinal RT_MANGLER(RTCrDigestFinal)
+# define RTCrDigestGetConsumedSize RT_MANGLER(RTCrDigestGetConsumedSize)
+# 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 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 RTCrRsaPublicKey_CheckSanity RT_MANGLER(RTCrRsaPublicKey_CheckSanity)
+# define RTCrPemFindFirstSectionInContent RT_MANGLER(RTCrPemFindFirstSectionInContent)
+# define RTCrPemFreeSections RT_MANGLER(RTCrPemFreeSections)
+# define RTCrPemParseContent RT_MANGLER(RTCrPemParseContent)
+# define RTCrPemReadFile RT_MANGLER(RTCrPemReadFile)
+# define RTCrPkcs7Attribute_DecodeAsn1 RT_MANGLER(RTCrPkcs7Attribute_DecodeAsn1)
+# define RTCrPkcs7Attributes_DecodeAsn1 RT_MANGLER(RTCrPkcs7Attributes_DecodeAsn1)
+# define RTCrPkcs7ContentInfo_DecodeAsn1 RT_MANGLER(RTCrPkcs7ContentInfo_DecodeAsn1)
+# define RTCrPkcs7DigestInfo_DecodeAsn1 RT_MANGLER(RTCrPkcs7DigestInfo_DecodeAsn1)
+# define RTCrPkcs7IssuerAndSerialNumber_DecodeAsn1 RT_MANGLER(RTCrPkcs7IssuerAndSerialNumber_DecodeAsn1)
+# define RTCrPkcs7SignedData_DecodeAsn1 RT_MANGLER(RTCrPkcs7SignedData_DecodeAsn1)
+# 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 RTCrPkcs7VerifyCertCallbackCodeSigning RT_MANGLER(RTCrPkcs7VerifyCertCallbackCodeSigning)
+# define RTCrPkcs7VerifyCertCallbackDefault RT_MANGLER(RTCrPkcs7VerifyCertCallbackDefault)
+# define RTCrPkcs7VerifySignedData RT_MANGLER(RTCrPkcs7VerifySignedData)
+# 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 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 RTCrPkixPubKeyVerifySignature RT_MANGLER(RTCrPkixPubKeyVerifySignature)
+# define RTCrPkixPubKeyVerifySignedDigest RT_MANGLER(RTCrPkixPubKeyVerifySignedDigest)
+# define RTCrSpcAttributeTypeAndOptionalValue_DecodeAsn1 RT_MANGLER(RTCrSpcAttributeTypeAndOptionalValue_DecodeAsn1)
+# define RTCrSpcIndirectDataContent_DecodeAsn1 RT_MANGLER(RTCrSpcIndirectDataContent_DecodeAsn1)
+# define RTCrSpcLink_DecodeAsn1 RT_MANGLER(RTCrSpcLink_DecodeAsn1)
+# define RTCrSpcPeImageData_DecodeAsn1 RT_MANGLER(RTCrSpcPeImageData_DecodeAsn1)
+# 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_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 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 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 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 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 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 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 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 RTUtf16Copy RT_MANGLER(RTUtf16Copy)
+# define RTUtf16CopyAscii RT_MANGLER(RTUtf16CopyAscii)
+# define RTUtf16Cat RT_MANGLER(RTUtf16Cat)
+# define RTUtf16CatAscii RT_MANGLER(RTUtf16CatAscii)
+# 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 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_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_aRTCrX509CertificateMarkers RT_MANGLER(g_aRTCrX509CertificateMarkers)
+# define g_cRTCrX509CertificateMarkers RT_MANGLER(g_cRTCrX509CertificateMarkers)
+
+#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
+
--- /dev/null
+/** @file
+ * IPRT - Memory Management and Manipulation.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_mem_h
+#define ___iprt_mem_h
+
+
+#include <iprt/cdefs.h>
+#include <iprt/types.h>
+
+
+#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;
+
+/** @} */
+
+
+/**
+ * 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;
+
+/**
+ * Frees memory.
+ *
+ * @param pv Pointer to memory block.
+ */
+RTDECL(void) RTMemFree(void *pv) RT_NO_THROW_PROTO;
+
+
+
+/** @name RTR0MemAllocEx and RTR0MemAllocExTag flags.
+ * @{ */
+/** The returned memory should be zeroed. */
+#define RTMEMALLOCEX_FLAGS_ZEROED RT_BIT(0)
+/** It must be load code into the returned memory block and execute it. */
+#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;
+
+
+
+/**
+ * Allocates memory which may contain code (default tag).
+ *
+ * @returns Pointer to the allocated memory.
+ * @returns NULL on failure.
+ * @param cb Size in bytes of the memory block to allocate.
+ */
+#define RTMemExecAlloc(cb) RTMemExecAllocTag((cb), RTMEM_TAG)
+
+/**
+ * Allocates memory which may contain code (custom tag).
+ *
+ * @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.
+ */
+RTDECL(void *) RTMemExecAllocTag(size_t cb, const char *pszTag) RT_NO_THROW_PROTO;
+
+/**
+ * Free executable/read/write memory allocated by RTMemExecAlloc().
+ *
+ * @param pv Pointer to memory block.
+ * @param cb The allocation size.
+ */
+RTDECL(void) RTMemExecFree(void *pv, size_t cb) RT_NO_THROW_PROTO;
+
+#if defined(IN_RING0) && defined(RT_ARCH_AMD64) && defined(RT_OS_LINUX)
+/**
+ * Donate read+write+execute memory to the exec heap.
+ *
+ * This API is specific to AMD64 and Linux/GNU. A kernel module that desires to
+ * use RTMemExecAlloc on AMD64 Linux/GNU will have to donate some statically
+ * allocated memory in the module if it wishes for GCC generated code to work.
+ * GCC can only generate modules that work in the address range ~2GB to ~0
+ * currently.
+ *
+ * The API only accept one single donation.
+ *
+ * @returns IPRT status code.
+ * @param pvMemory Pointer to the memory block.
+ * @param cb The size of the memory block.
+ */
+RTR0DECL(int) RTR0MemExecDonate(void *pvMemory, size_t cb) RT_NO_THROW_PROTO;
+#endif /* R0+AMD64+LINUX */
+
+/**
+ * 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;
+
+/**
+ * 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;
+
+#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 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;
+
+/**
+ * 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;
+
+/**
+ * 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) 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) \
+ { \
+ 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 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 RTMemFree(pv) RTMemEfFree((pv), 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 RTMemTmpFreeTag.
+ * @copydoc RTMemTmpFree
+ */
+RTDECL(void) RTMemEfTmpFreeNP(void *pv) 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 RTMemFree.
+ * @copydoc RTMemFree
+ */
+RTDECL(void) RTMemEfFreeNP(void *pv) 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
+
--- /dev/null
+/** @file
+ * IPRT - Memory Objects (Ring-0).
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_memobj_h
+#define ___iprt_memobj_h
+
+#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);
+
+/**
+ * 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.
+ */
+#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.
+ * @param pszTag Allocation tag used for statistics and such.
+ */
+RTR0DECL(int) RTR0MemObjAllocPageTag(PRTR0MEMOBJ pMemObj, size_t cb, bool fExecutable, const char *pszTag);
+
+/**
+ * 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.
+ */
+#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.
+ * @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.
+ */
+#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.
+ * @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_R0PROCESS 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_R0PROCESS 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_R0PROCESS 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_R0PROCESS 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_R0PROCESS 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_R0PROCESS 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);
+
+/**
+ * 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
+
--- /dev/null
+/** @file
+ * IPRT - Multiprocessor.
+ */
+
+/*
+ * Copyright (C) 2008-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_mp_h
+#define ___iprt_mp_h
+
+#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 DECLCALLBACK(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 a 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 DECLCALLBACK(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
+
--- /dev/null
+/** @file
+ * IPRT - Network Protocols.
+ */
+
+/*
+ * Copyright (C) 2008-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_net_h
+#define ___iprt_net_h
+
+#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);
+
+/**
+ * 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);
+
+
+/**
+ * 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 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
+
--- /dev/null
+/** @file
+ * IPRT / No-CRT - Our own limits header.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_nocrt_limits_h
+#define ___iprt_nocrt_limits_h
+
+#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)
+# 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)
+# 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)
+
+#if ARCH_BITS == 32
+# define SIZE_T_MAX 0xffffffffU
+# define SSIZE_MAX 0x7fffffff
+#elif ARCH_BITS == 64
+# define SIZE_T_MAX UINT64_C(0xffffffffffffffff)
+# define SSIZE_MAX INT64_C(0x7fffffffffffffff)
+#else
+# error "huh?"
+#endif
+
+/*#define OFF_MAX __OFF_MAX
+#define OFF_MIN __OFF_MIN*/
+
+#endif
+
--- /dev/null
+/** @file
+ * IPRT - Parameter Definitions.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_param_h
+#define ___iprt_param_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
+#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
+#else
+# define PAGE_SHIFT 12
+#endif
+
+/**
+ * i386 Page offset mask.
+ *
+ * Do NOT one-complement this for whatever purpose. You may get a 32-bit const when you want a 64-bit one.
+ * Use PAGE_BASE_MASK, PAGE_BASE_GC_MASK, PAGE_BASE_HC_MASK, PAGE_ADDRESS() or X86_PTE_PAE_PG_MASK.
+ */
+#if defined(RT_ARCH_SPARC64)
+# define PAGE_OFFSET_MASK 0x1fff
+#else
+# define PAGE_OFFSET_MASK 0xfff
+#endif
+
+/**
+ * Page address mask for the guest context POINTERS.
+ * @remark Physical addresses are always masked using X86_PTE_PAE_PG_MASK!
+ */
+#define PAGE_BASE_GC_MASK (~(RTGCUINTPTR)PAGE_OFFSET_MASK)
+
+/**
+ * Page address mask for the host context POINTERS.
+ * @remark Physical addresses are always masked using X86_PTE_PAE_PG_MASK!
+ */
+#define PAGE_BASE_HC_MASK (~(RTHCUINTPTR)PAGE_OFFSET_MASK)
+
+/**
+ * Page address mask for the both context 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 (~(RTUINTPTR)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_path_h) || defined(DOXYGEN_RUNNING)
+# define RTPATH_MAX (4096 + 4) /* (PATH_MAX + 1) on linux w/ some alignment */
+#endif
+
+/** @} */
+
+
+/** @} */
+
+#endif
+
--- /dev/null
+/** @file
+ * IPRT - Path Manipulation.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_path_h
+#define ___iprt_path_h
+
+#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_param_h) || defined(DOXYGEN_RUNNING)
+# define RTPATH_MAX (4096 + 4) /* (PATH_MAX + 1) on linux w/ some alignment */
+#endif
+
+/** @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)
+/** @} */
+
+/** 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) )
+
+
+/**
+ * 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 cchAbsPath Size of the buffer.
+ */
+RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cchAbsPath);
+
+/**
+ * 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.
+ */
+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 pszAbsPath Where to store the absolute path.
+ * @param cchAbsPath Size of the buffer.
+ */
+RTDECL(int) RTPathAbsEx(const char *pszBase, const char *pszPath, char *pszAbsPath, size_t cchAbsPath);
+
+/**
+ * Same as RTPathAbsEx only the result is RTStrDup()'ed.
+ *
+ * @returns Pointer to the absolute path. Use RTStrFree() to free this string.
+ * @returns 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.
+ */
+RTDECL(char *) RTPathAbsExDup(const char *pszBase, const char *pszPath);
+
+/**
+ * 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);
+
+/**
+ * Ensures that the path has a trailing path separator such that file names can
+ * be appended without further work.
+ *
+ * This can be helpful when preparing for efficiently combining a directory path
+ * with the filenames returned by RTDirRead. The return value gives you the
+ * position at which you copy the RTDIRENTRY::szName to construct a valid path
+ * to it.
+ *
+ * @returns The length of the path, 0 on buffer overflow.
+ * @param pszPath The path.
+ * @param cbPath The length of the path buffer @a pszPath points to.
+ */
+RTDECL(size_t) RTPathEnsureTrailingSeparator(char *pszPath, size_t cbPath);
+
+/**
+ * Changes all the slashes in the specified path to DOS style.
+ *
+ * Unless @a fForce is set, nothing will be done when on a UNIX flavored system
+ * 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);
+
+/**
+ * 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);
+
+/**
+ * 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);
+
+/**
+ * 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);
+
+/**
+ * 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)
+
+
+/** 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 lenght 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! */
+ struct
+ {
+ /** The offset of the component. */
+ uint16_t off;
+ /** The length of the component. */
+ uint16_t cch;
+ } aComps[1];
+} RTPATHPARSED;
+/** Pointer to to a parsed path result. */
+typedef RTPATHPARSED *PRTPATHPARSED;
+/** Pointer to to a const parsed path result. */
+typedef RTPATHPARSED *PCRTPATHPARSED;
+
+
+/**
+ * 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 @a cbDstPath is less than or equal to
+ * RTPATHPARSED::cchPath.
+ *
+ * @param pszSrcPath The source path.
+ * @param pParsed The parser output for @a pszSrcPath.
+ * @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). */
+ char *apszComps[1];
+} 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.
+ *
+ * @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);
+
+/**
+ * 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.
+ *
+ */
+RTDECL(int) RTPathJoinEx(char *pszPathDst, size_t cbPathDst,
+ const char *pszPathSrc, size_t cchPathSrcMax,
+ const char *pszAppend, size_t cchAppendMax);
+
+/**
+ * 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 DECLCALLBACK(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 pszPathTo The path to reach with the created relative path.
+ */
+RTDECL(int) RTPathCalcRelative(char *pszPathDst, size_t cbPathDst,
+ const char *pszPathFrom,
+ 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);
+
+#endif /* IN_RING3 */
+
+/** @} */
+
+RT_C_DECLS_END
+
+#endif
+
--- /dev/null
+/** @file
+ * IPRT - Power management.
+ */
+
+/*
+ * Copyright (C) 2008-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_power_h
+#define ___iprt_power_h
+
+#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 DECLCALLBACK(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
+
--- /dev/null
+/** @file
+ * IPRT - Process Management.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_process_h
+#define ___iprt_process_h
+
+#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
+
+
+#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 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, 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.
+ * @remarks On non-windows platforms, the resulting environment maybe very
+ * different from what you see in your shell. Among other reasons,
+ * we cannot run shell profile scripts which typically sets up the
+ * environment. */
+#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)
+/** Valid flag mask. */
+#define RTPROC_FLAGS_VALID_MASK UINT32_C(0x1ff)
+/** @} */
+
+
+/**
+ * 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.
+ */
+RTR3DECL(const char *) RTProcShortName(void);
+
+/**
+ * Gets 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.
+ */
+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
+
--- /dev/null
+/** @file
+ * IPRT - Semaphore.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_semaphore_h
+#define ___iprt_semaphore_h
+
+#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.
+ */
+RTDECL(int) RTSemEventSignal(RTSEMEVENT hEventSem);
+
+/**
+ * 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.
+ */
+RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem);
+
+/**
+ * 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_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 driver verifier.
+ *
+ * @{ */
+
+/**
+ * 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.
+ *
+ * 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 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_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
+
--- /dev/null
+/** @file
+ * IPRT - Spinlocks.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_spinlock_h
+#define ___iprt_spinlock_h
+
+#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
+
--- /dev/null
+/** @file
+ * IPRT - stdarg.h wrapper.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_stdarg_h
+#define ___iprt_stdarg_h
+
+#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
+# else
+# include <stdarg.h>
+# endif
+#endif
+
+/*
+ * MSC doesn't implement va_copy.
+ */
+#ifndef va_copy
+# define va_copy(dst, src) do { (dst) = (src); } while (0) /** @todo check AMD64 */
+#endif
+
+#endif
+
--- /dev/null
+/** @file
+ * IPRT - stdint.h wrapper (for backlevel compilers like MSC).
+ */
+
+/*
+ * Copyright (C) 2009-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef __iprt_stdint_h
+#define __iprt_stdint_h
+
+#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_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
+
+# 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(DOXYGEN_RUNNING)
+# if ARCH_BITS == 32 \
+ || defined(RT_OS_LINUX) \
+ || defined(RT_OS_FREEBSD)
+# if !defined(_INTPTR_T_DECLARED) && !defined(_INTPTR_T)
+typedef signed long intptr_t;
+# endif
+# if !defined(_UINTPTR_T_DECLARED) && !defined(_UINTPTR_T)
+typedef unsigned long uintptr_t;
+# endif
+# else
+# if !defined(_INTPTR_T_DECLARED) && !defined(_INTPTR_T)
+typedef int64_t intptr_t;
+# endif
+# if !defined(_UINTPTR_T_DECLARED) && !defined(_UINTPTR_T)
+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
+
--- /dev/null
+/** @file
+ * IPRT - String Manipulation.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_string_h
+#define ___iprt_string_h
+
+#include <iprt/cdefs.h>
+#include <iprt/types.h>
+#include <iprt/assert.h>
+#include <iprt/stdarg.h>
+#include <iprt/err.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
+# include <string.h>
+# undef ffs
+# undef strpbrk
+
+#else
+# include <string.h>
+#endif
+
+/* For the time being: */
+#include <iprt/utf16.h>
+#include <iprt/latin1.h>
+
+/*
+ * 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_LINUX) || !defined(_GNU_SOURCE)) && !defined(RT_OS_FREEBSD) && !defined(RT_OS_NETBSD)
+RT_C_DECLS_BEGIN
+void *memrchr(const char *pv, int ch, size_t cb);
+RT_C_DECLS_END
+#endif
+
+
+/** @def RT_USE_RTC_3629
+ * When defined the UTF-8 range will stop at 0x10ffff. If not defined, the
+ * range stops at 0x7fffffff.
+ * @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)
+
+
+
+/** @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 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 pszTag Allocation tag used for statistics and such.
+ */
+RTR3DECL(int) RTStrUtf8ToCurrentCPTag(char **ppszString, const char *pszString, 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);
+
+#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 ppszString 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(ppszString, pszString) RTStrDupExTag((ppszString), (pszString), RTSTR_TAG)
+
+/**
+ * Allocates a new copy of the given UTF-8 string (custom tag).
+ *
+ * @returns iprt status code.
+ * @param ppszString 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 **ppszString, 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);
+
+/**
+ * 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 replacement 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).
+ *
+ * @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);
+
+/**
+ * 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);
+
+
+/**
+ * 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++ = (unsigned 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!'.
+ * - \%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.
+ * - \%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.
+ * - \%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.
+ * - \%Rra - Takes an integer iprt status code as argument. Will insert the
+ * status code define + full description.
+ * - \%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.
+ * - \%Rwa - Takes a long Windows error code as argument. Will insert the
+ * error code define + full description.
+ *
+ * - \%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.
+ * - \%Rhra - Takes a COM/XPCOM error code as argument. Will insert the
+ * error code define + full description.
+ *
+ * - \%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.
+ *
+ * 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 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.
+ *
+ * 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 */
+# 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 DECLCALLBACK(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 DECLCALLBACK(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 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);
+
+
+
+/**
+ * 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 DECLCALLBACK(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.
+ */
+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.
+ */
+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.
+ */
+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.
+ */
+RTDECL(size_t) RTStrPrintfEx(PFNSTRFORMAT pfnFormat, void *pvArg, char *pszBuffer, size_t cchBuffer,
+ 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 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.
+ * @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 RTUtf16ICmpAscii
+ */
+RTDECL(int) RTStrICmpAscii(const char *psz1, const char *psz2);
+
+/**
+ * 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(int) 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(int) RTStrIStartsWith(const char *pszString, const char *pszStart);
+
+/**
+ * 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);
+
+RT_C_DECLS_END
+
+/** 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.
+ */
+#if defined(__cplusplus) && !defined(DOXYGEN_RUNNING)
+DECLINLINE(char const *) RTStrEnd(char const *pszString, size_t cchMax)
+{
+ /* Avoid potential issues with memchr seen in glibc.
+ * See sysdeps/x86_64/memchr.S in glibc versions older than 2.11 */
+ while (cchMax > RTSTR_MEMCHR_MAX)
+ {
+ char const *pszRet = (char const *)memchr(pszString, '\0', RTSTR_MEMCHR_MAX);
+ if (RT_LIKELY(pszRet))
+ return pszRet;
+ pszString += RTSTR_MEMCHR_MAX;
+ cchMax -= RTSTR_MEMCHR_MAX;
+ }
+ return (char const *)memchr(pszString, '\0', cchMax);
+}
+
+DECLINLINE(char *) RTStrEnd(char *pszString, size_t cchMax)
+#else
+DECLINLINE(char *) RTStrEnd(const char *pszString, size_t cchMax)
+#endif
+{
+ /* Avoid potential issues with memchr seen in glibc.
+ * See sysdeps/x86_64/memchr.S in glibc versions older than 2.11 */
+ while (cchMax > RTSTR_MEMCHR_MAX)
+ {
+ char *pszRet = (char *)memchr(pszString, '\0', RTSTR_MEMCHR_MAX);
+ if (RT_LIKELY(pszRet))
+ return pszRet;
+ pszString += RTSTR_MEMCHR_MAX;
+ cchMax -= RTSTR_MEMCHR_MAX;
+ }
+ return (char *)memchr(pszString, '\0', cchMax);
+}
+
+RT_C_DECLS_BEGIN
+
+/**
+ * Finds the offset at which a simple character first occurs in a string.
+ *
+ * @returns The offset of the first occurence or the terminator offset.
+ * @param pszHaystack The string to search.
+ * @param chNeedle The character to search for.
+ */
+DECLINLINE(size_t) RTStrOffCharOrTerm(const char *pszHaystack, char chNeedle)
+{
+ const char *psz = pszHaystack;
+ char ch;
+ while ( (ch = *psz) != chNeedle
+ && ch != '\0')
+ psz++;
+ return psz - pszHaystack;
+}
+
+
+/**
+ * Matches a simple string pattern.
+ *
+ * @returns true if the string matches the pattern, otherwise false.
+ *
+ * @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 uBase The base of the representation used.
+ * If 0 the function will look for known prefixes before defaulting to 10.
+ * @param pu64 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToUInt64Ex(const char *pszValue, char **ppszNext, unsigned uBase, 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 uBase The base of the representation used.
+ * If 0 the function will look for known prefixes before defaulting to 10.
+ * @param pu64 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToUInt64Full(const char *pszValue, unsigned uBase, 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 uBase The base of the representation used.
+ * If 0 the function will look for known prefixes before defaulting to 10.
+ * @param pu32 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToUInt32Ex(const char *pszValue, char **ppszNext, unsigned uBase, 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 uBase The base of the representation used.
+ * If 0 the function will look for known prefixes before defaulting to 10.
+ * @param pu32 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToUInt32Full(const char *pszValue, unsigned uBase, uint32_t *pu32);
+
+/**
+ * Converts a string representation of a number to a 64-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 uBase The base of the representation used.
+ * If 0 the function will look for known prefixes before defaulting to 10.
+ * @param pu16 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToUInt16Ex(const char *pszValue, char **ppszNext, unsigned uBase, 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 uBase The base of the representation used.
+ * If 0 the function will look for known prefixes before defaulting to 10.
+ * @param pu16 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToUInt16Full(const char *pszValue, unsigned uBase, 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 uBase The base of the representation used.
+ * If 0 the function will look for known prefixes before defaulting to 10.
+ * @param pu8 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToUInt8Ex(const char *pszValue, char **ppszNext, unsigned uBase, 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 uBase The base of the representation used.
+ * If 0 the function will look for known prefixes before defaulting to 10.
+ * @param pu8 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToUInt8Full(const char *pszValue, unsigned uBase, 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 uBase The base of the representation used.
+ * If 0 the function will look for known prefixes before defaulting to 10.
+ * @param pi64 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToInt64Ex(const char *pszValue, char **ppszNext, unsigned uBase, 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 uBase The base of the representation used.
+ * If 0 the function will look for known prefixes before defaulting to 10.
+ * @param pi64 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToInt64Full(const char *pszValue, unsigned uBase, 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 uBase The base of the representation used.
+ * If 0 the function will look for known prefixes before defaulting to 10.
+ * @param pi32 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToInt32Ex(const char *pszValue, char **ppszNext, unsigned uBase, 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 uBase The base of the representation used.
+ * If 0 the function will look for known prefixes before defaulting to 10.
+ * @param pi32 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToInt32Full(const char *pszValue, unsigned uBase, 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 uBase The base of the representation used.
+ * If 0 the function will look for known prefixes before defaulting to 10.
+ * @param pi16 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToInt16Ex(const char *pszValue, char **ppszNext, unsigned uBase, 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 uBase The base of the representation used.
+ * If 0 the function will look for known prefixes before defaulting to 10.
+ * @param pi16 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToInt16Full(const char *pszValue, unsigned uBase, 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 uBase The base of the representation used.
+ * If 0 the function will look for known prefixes before defaulting to 10.
+ * @param pi8 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToInt8Ex(const char *pszValue, char **ppszNext, unsigned uBase, 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 uBase The base of the representation used.
+ * If 0 the function will look for known prefixes before defaulting to 10.
+ * @param pi8 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToInt8Full(const char *pszValue, unsigned uBase, 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);
+
+/**
+ * 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 Must be zero, reserved for future use.
+ */
+RTDECL(int) RTStrConvertHexBytes(char const *pszHex, void *pv, size_t cb, uint32_t fFlags);
+
+/** @} */
+
+
+/** @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
+{
+ /** Hash key. Don't touch. */
+ uint32_t Key;
+ /** 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 key. Don't touch. */
+ PRTSTRSPACECORE pList;
+ /** 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 DECLCALLBACK(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);
+
+/** @} */
+
+/** @} */
+
+RT_C_DECLS_END
+
+#endif
+
--- /dev/null
+/** @file
+ * IPRT - Threads.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_thread_h
+#define ___iprt_thread_h
+
+#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;
+
+
+#ifndef IN_RC
+
+/**
+ * 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 DECLCALLBACK(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,
+
+ /** Mask of valid flags, use for validation. */
+ RTTHREADFLAGS_MASK = RT_BIT(0)
+} RTTHREADFLAGS;
+
+
+/**
+ * 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 */
+/** @copydoc RTThreadCreate */
+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 pszName 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 pszName 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 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);
+
+/**
+ * Checks if the calling thread is known to IPRT.
+ *
+ * @returns @c true if it is, @c false if it isn't.
+ */
+RTDECL(bool) RTThreadIsOperational(void);
+
+/**
+ * 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 signal the thread, attempting to interrupt whatever it's currently
+ * doing. This is *NOT* implemented on all platforms and may cause unresolved
+ * symbols during linking or VERR_NOT_IMPLEMENTED at runtime.
+ *
+ * @returns IPRT status code.
+ *
+ * @param hThread The thread to poke. This must not be the
+ * calling thread.
+ */
+RTDECL(int) RTThreadPoke(RTTHREAD hThread);
+
+# 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.
+ */
+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 DECLCALLBACK(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 DECLCALLBACK(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. WARNING! This feature may not
+ * be implemented everywhere.
+ */
+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 */
+
+/** @} */
+
+RT_C_DECLS_END
+
+#endif
+
--- /dev/null
+/** @file
+ * IPRT - Time.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_time_h
+#define ___iprt_time_h
+
+#include <iprt/cdefs.h>
+#include <iprt/types.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;
+}
+
+
+/* PORTME: Add struct timeval guard macro here. */
+#if defined(RTTIME_INCL_TIMEVAL) || defined(_STRUCT_TIMEVAL) || defined(_SYS__TIMEVAL_H_) || defined(_SYS_TIME_H) || defined(_TIMEVAL) || defined(_LINUX_TIME_H) \
+ || (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(_STRUCT_TIMESPEC) || defined(_SYS__TIMESPEC_H_) || defined(TIMEVAL_TO_TIMESPEC) || defined(_TIMESPEC) \
+ || (defined(RT_OS_NETBSD) && defined(_SYS_TIME_H_))
+/**
+ * Gets the time as POSIX timespec.
+ *
+ * @returns pTime.
+ * @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 */
+
+
+
+/** 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(uint64_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
+
+
+/** 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);
+
+/** @} */
+
+
+/**
+ * Exploded time.
+ */
+#pragma pack(1)
+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;
+ /** UCT time offset in minutes (-840-840).
+ * @remarks The implementation of RTTimeLocal* isn't quite there yet, so this might not be 100% correct. */
+ int32_t offUTC;
+} RTTIME;
+#pragma pack()
+/** 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 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);
+
+/**
+ * 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 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);
+
+/**
+ * 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);
+
+/**
+ * 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);
+
+/**
+ * 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);
+
+/** @name RTTimeNanoTS GIP worker functions, for TM.
+ * @{ */
+/** 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.
+ */
+ DECLCALLBACKMEMBER(uint64_t, pfnRediscover)(PRTTIMENANOTSDATA pData);
+
+ /**
+ * Callback for when some CPU index related stuff goes wrong.
+ *
+ * @returns Nanosecond timestamp.
+ * @param pData Pointer to this structure.
+ * @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, 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));
+ DECLR3CALLBACKMEMBER(uint64_t, pfnBadCpuIndex,(PRTTIMENANOTSDATA pData, 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));
+ DECLR0CALLBACKMEMBER(uint64_t, pfnBadCpuIndex,(PRTTIMENANOTSDATA pData, 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));
+ DECLRCCALLBACKMEMBER(uint64_t, pfnBadCpuIndex,(PRTTIMENANOTSDATA pData, 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 DECLCALLBACK(uint64_t) FNTIMENANOTSINTERNAL(PRTTIMENANOTSDATA pData);
+/** Pointer to an internal RTTimeNanoTS worker (assembly). */
+typedef FNTIMENANOTSINTERNAL *PFNTIMENANOTSINTERNAL;
+RTDECL(uint64_t) RTTimeNanoTSLegacySyncInvarNoDelta(PRTTIMENANOTSDATA pData);
+RTDECL(uint64_t) RTTimeNanoTSLFenceSyncInvarNoDelta(PRTTIMENANOTSDATA pData);
+#ifdef IN_RING3
+RTDECL(uint64_t) RTTimeNanoTSLegacyAsyncUseApicId(PRTTIMENANOTSDATA pData);
+RTDECL(uint64_t) RTTimeNanoTSLegacyAsyncUseRdtscp(PRTTIMENANOTSDATA pData);
+RTDECL(uint64_t) RTTimeNanoTSLegacyAsyncUseRdtscpGroupChNumCl(PRTTIMENANOTSDATA pData);
+RTDECL(uint64_t) RTTimeNanoTSLegacyAsyncUseIdtrLim(PRTTIMENANOTSDATA pData);
+RTDECL(uint64_t) RTTimeNanoTSLegacySyncInvarWithDeltaUseApicId(PRTTIMENANOTSDATA pData);
+RTDECL(uint64_t) RTTimeNanoTSLegacySyncInvarWithDeltaUseRdtscp(PRTTIMENANOTSDATA pData);
+RTDECL(uint64_t) RTTimeNanoTSLegacySyncInvarWithDeltaUseIdtrLim(PRTTIMENANOTSDATA pData);
+RTDECL(uint64_t) RTTimeNanoTSLFenceAsyncUseApicId(PRTTIMENANOTSDATA pData);
+RTDECL(uint64_t) RTTimeNanoTSLFenceAsyncUseRdtscp(PRTTIMENANOTSDATA pData);
+RTDECL(uint64_t) RTTimeNanoTSLFenceAsyncUseRdtscpGroupChNumCl(PRTTIMENANOTSDATA pData);
+RTDECL(uint64_t) RTTimeNanoTSLFenceAsyncUseIdtrLim(PRTTIMENANOTSDATA pData);
+RTDECL(uint64_t) RTTimeNanoTSLFenceSyncInvarWithDeltaUseApicId(PRTTIMENANOTSDATA pData);
+RTDECL(uint64_t) RTTimeNanoTSLFenceSyncInvarWithDeltaUseRdtscp(PRTTIMENANOTSDATA pData);
+RTDECL(uint64_t) RTTimeNanoTSLFenceSyncInvarWithDeltaUseIdtrLim(PRTTIMENANOTSDATA pData);
+#else
+RTDECL(uint64_t) RTTimeNanoTSLegacyAsync(PRTTIMENANOTSDATA pData);
+RTDECL(uint64_t) RTTimeNanoTSLegacySyncInvarWithDelta(PRTTIMENANOTSDATA pData);
+RTDECL(uint64_t) RTTimeNanoTSLFenceAsync(PRTTIMENANOTSDATA pData);
+RTDECL(uint64_t) RTTimeNanoTSLFenceSyncInvarWithDelta(PRTTIMENANOTSDATA pData);
+#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);
+
+/** @} */
+
+RT_C_DECLS_END
+
+#endif
+
--- /dev/null
+/** @file
+ * IPRT - Timer.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_timer_h
+#define ___iprt_timer_h
+
+
+#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 DECLCALLBACK(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 DECLCALLBACK(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
--- /dev/null
+/** @file
+ * IPRT - Types.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_types_h
+#define ___iprt_types_h
+
+#include <iprt/cdefs.h>
+#include <iprt/stdint.h>
+#include <iprt/stdarg.h>
+
+/*
+ * Include standard C types.
+ */
+#ifndef IPRT_NO_CRT
+
+# 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)
+ /*
+ * 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
+
+# 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.
+ */
+# include <stddef.h>
+# 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
+# else
+# include <stddef.h>
+# include <sys/types.h>
+# endif
+
+
+/* Define any types missing from sys/types.h on windows. */
+# ifdef _MSC_VER
+# undef ssize_t
+ typedef intptr_t 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
+# if (defined(RT_OS_DARWIN) || defined(RT_OS_HAIKU)) && (defined(_STDBOOL_H) || defined(__STDBOOL_H))
+# undef bool
+# endif
+typedef _Bool bool;
+# endif
+# else
+typedef unsigned char bool;
+# endif
+# ifndef true
+# define true (1)
+# endif
+# ifndef false
+# define false (0)
+# endif
+#endif
+
+/**
+ * 128-bit unsigned integer.
+ */
+#if defined(__GNUC__) && defined(RT_ARCH_AMD64)
+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.
+ */
+#if defined(__GNUC__) && defined(RT_ARCH_AMD64)
+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 view. */
+ uint16_t au16[1];
+ /** 8-bit view. */
+ uint8_t au8[2];
+ /** 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;
+} RTUINT16U;
+/** Pointer to a 16-bit unsigned integer union. */
+typedef RTUINT16U *PRTUINT16U;
+/** Pointer to a const 32-bit unsigned integer union. */
+typedef const RTUINT16U *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;
+
+ /** 32-bit view. */
+ uint32_t au32[1];
+ /** 16-bit view. */
+ uint16_t au16[2];
+ /** 8-bit view. */
+ uint8_t au8[4];
+} RTUINT32U;
+/** Pointer to a 32-bit unsigned integer union. */
+typedef RTUINT32U *PRTUINT32U;
+/** Pointer to a const 32-bit unsigned integer union. */
+typedef const RTUINT32U *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;
+
+ /** 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];
+} RTUINT64U;
+/** Pointer to a 64-bit unsigned integer union. */
+typedef RTUINT64U *PRTUINT64U;
+/** Pointer to a const 64-bit unsigned integer union. */
+typedef const RTUINT64U *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;
+
+ /** 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];
+} RTUINT128U;
+#pragma pack()
+/** Pointer to a 128-bit unsigned integer union. */
+typedef RTUINT128U *PRTUINT128U;
+/** Pointer to a const 128-bit unsigned integer union. */
+typedef const RTUINT128U *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;
+
+ /** 128-bit view. */
+ RTUINT128U au128[2];
+ /** 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];
+} RTUINT256U;
+#pragma pack()
+/** Pointer to a 256-bit unsigned integer union. */
+typedef RTUINT256U *PRTUINT256U;
+/** Pointer to a const 256-bit unsigned integer union. */
+typedef const RTUINT256U *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 *PRTUINT512U;
+/** Pointer to a const 512-bit unsigned integer union. */
+typedef const RTUINT512U *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))
+
+
+/**
+ * Double precision floating point format (64-bit).
+ */
+typedef union RTFLOAT64U
+{
+#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
+ /** Double view. */
+ double rd;
+#endif
+ /** Format using regular bitfields. */
+ struct
+ {
+# ifdef RT_BIG_ENDIAN
+ /** The sign indicator. */
+ uint32_t fSign : 1;
+ /** The exponent (offseted by 1023). */
+ uint32_t uExponent : 11;
+ /** The fraction, bits 32 thru 51. */
+ uint32_t u20FractionHigh : 20;
+ /** The fraction, bits 0 thru 31. */
+ uint32_t u32FractionLow;
+# else
+ /** The fraction, bits 0 thru 31. */
+ uint32_t u32FractionLow;
+ /** The fraction, bits 32 thru 51. */
+ uint32_t u20FractionHigh : 20;
+ /** The exponent (offseted 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 (offseted 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 (offseted by 1023). */
+ RT_GCC_EXTENSION uint64_t uExponent : 11;
+ /** The sign indicator. */
+ RT_GCC_EXTENSION uint64_t fSign : 1;
+# endif
+ } s64;
+#endif
+
+ /** 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 *PRTFLOAT64U;
+/** Pointer to a const double precision floating point format union. */
+typedef const RTFLOAT64U *PCRTFLOAT64U;
+
+
+#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
+ /** The sign indicator. */
+ RT_GCC_EXTENSION uint16_t fSign : 1;
+ /** The exponent (offseted by 16383). */
+ RT_GCC_EXTENSION uint16_t uExponent : 15;
+ /** The mantissa. */
+ uint64_t u64Mantissa;
+# else
+ /** The mantissa. */
+ uint64_t u64Mantissa;
+ /** The exponent (offseted by 16383). */
+ RT_GCC_EXTENSION uint16_t uExponent : 15;
+ /** The sign indicator. */
+ RT_GCC_EXTENSION uint16_t fSign : 1;
+# endif
+ } 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];
+} RTFLOAT80U;
+#pragma pack()
+/** Pointer to a extended precision floating point format union. */
+typedef RTFLOAT80U *PRTFLOAT80U;
+/** Pointer to a const extended precision floating point format union. */
+typedef const RTFLOAT80U *PCRTFLOAT80U;
+
+
+/**
+ * A variant of RTFLOAT80U that may be larger than 80-bits depending on how the
+ * compiler implements long double.
+ */
+#pragma pack(1)
+typedef union RTFLOAT80U2
+{
+#ifdef RT_COMPILER_WITH_80BIT_LONG_DOUBLE
+ /** Long double view. */
+ long double lrd;
+#endif
+ /** Format using bitfields. */
+ RT_GCC_EXTENSION struct
+ {
+#ifdef RT_BIG_ENDIAN
+ /** The sign indicator. */
+ RT_GCC_EXTENSION uint16_t fSign : 1;
+ /** The exponent (offseted by 16383). */
+ RT_GCC_EXTENSION uint16_t uExponent : 15;
+ /** The mantissa. */
+ uint64_t u64Mantissa;
+#else
+ /** The mantissa. */
+ uint64_t u64Mantissa;
+ /** The exponent (offseted by 16383). */
+ RT_GCC_EXTENSION uint16_t uExponent : 15;
+ /** The sign indicator. */
+ RT_GCC_EXTENSION uint16_t fSign : 1;
+#endif
+ } s;
+
+ /** Bitfield exposing the J bit and the fraction. */
+ RT_GCC_EXTENSION struct
+ {
+#ifdef RT_BIG_ENDIAN
+ /** The sign indicator. */
+ RT_GCC_EXTENSION uint16_t fSign : 1;
+ /** The exponent (offseted by 16383). */
+ RT_GCC_EXTENSION uint16_t uExponent : 15;
+ /** The J bit, aka the integer bit. */
+ uint32_t fInteger;
+ /** The fraction, bits 32 thru 62. */
+ uint32_t u31FractionHigh : 31;
+ /** The fraction, bits 0 thru 31. */
+ uint32_t u32FractionLow : 32;
+#else
+ /** The fraction, bits 0 thru 31. */
+ uint32_t u32FractionLow : 32;
+ /** The fraction, bits 32 thru 62. */
+ uint32_t u31FractionHigh : 31;
+ /** The J bit, aka the integer bit. */
+ uint32_t fInteger;
+ /** The exponent (offseted 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
+ /** The sign indicator. */
+ RT_GCC_EXTENSION uint16_t fSign : 1;
+ /** The exponent (offseted 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 u63Fraction : 63;
+# else
+ /** The fraction. */
+ RT_GCC_EXTENSION uint64_t u63Fraction : 63;
+ /** The J bit, aka the integer bit. */
+ RT_GCC_EXTENSION uint64_t fInteger : 1;
+ /** The exponent (offseted 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];
+} RTFLOAT80U2;
+#pragma pack()
+/** Pointer to a extended precision floating point format union, 2nd
+ * variant. */
+typedef RTFLOAT80U2 *PRTFLOAT80U2;
+/** Pointer to a const extended precision floating point format union, 2nd
+ * variant. */
+typedef const RTFLOAT80U2 *PCRTFLOAT80U2;
+
+#endif /* uint16_t bitfields doesn't work */
+
+
+/** Generic function type.
+ * @see PFNRT
+ */
+typedef DECLCALLBACK(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;
+
+/** Millisecond interval. */
+typedef uint32_t RTMSINTERVAL;
+/** Pointer to a millisecond interval. */
+typedef RTMSINTERVAL *PRTMSINTERVAL;
+/** Pointer to a const millisecond interval. */
+typedef const RTMSINTERVAL *PCRTMSINTERVAL;
+
+/** Pointer to a time spec structure. */
+typedef struct RTTIMESPEC *PRTTIMESPEC;
+/** Pointer to a const time spec structure. */
+typedef const struct RTTIMESPEC *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 *PRTINTPTR;
+/** Pointer const to signed integer which can contain both GC and HC pointers. */
+typedef const RTINTPTR *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 *PRTUINTPTR;
+/** Pointer const to unsigned integer which can contain both GC and HC pointers. */
+typedef const RTUINTPTR *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 *PRTINT;
+/** Pointer to const signed integer. */
+typedef const RTINT *PCRTINT;
+
+/** Unsigned integer. */
+typedef uint32_t RTUINT;
+/** Pointer to unsigned integer. */
+typedef RTUINT *PRTUINT;
+/** Pointer to const unsigned integer. */
+typedef const RTUINT *PCRTUINT;
+
+/** A file offset / size (off_t). */
+typedef int64_t RTFOFF;
+/** Pointer to a file offset / size. */
+typedef RTFOFF *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 *PRTFMODE;
+
+/** Device unix number. */
+typedef uint32_t RTDEV;
+/** Pointer to a device unix number. */
+typedef RTDEV *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 *PRTINODE;
+
+/** User id. */
+typedef uint32_t RTUID;
+/** Pointer to a user id. */
+typedef RTUID *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 *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 *PRTIOPORT;
+/** Pointer to const I/O Port. */
+typedef const RTIOPORT *PCRTIOPORT;
+
+/** Selector. */
+typedef uint16_t RTSEL;
+/** Pointer to selector. */
+typedef RTSEL *PRTSEL;
+/** Pointer to const selector. */
+typedef const RTSEL *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 *PRTFAR16;
+/** Pointer to const Far 16-bit pointer. */
+typedef const RTFAR16 *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 *PRTFAR32;
+/** Pointer to const Far 32-bit pointer. */
+typedef const RTFAR32 *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 *PRTFAR64;
+/** Pointer to const Far 64-bit pointer. */
+typedef const RTFAR64 *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 *PRTHCINT;
+/** Pointer to const HC Natural signed integer.
+ * @deprecated silly type. */
+typedef const RTHCINT *PCRTHCINT;
+
+/** HC Natural unsigned integer.
+ * @deprecated silly type. */
+typedef uint32_t RTHCUINT;
+/** Pointer to HC Natural unsigned integer.
+ * @deprecated silly type. */
+typedef RTHCUINT *PRTHCUINT;
+/** Pointer to const HC Natural unsigned integer.
+ * @deprecated silly type. */
+typedef const RTHCUINT *PCRTHCUINT;
+
+
+/** Signed integer which can contain a HC pointer. */
+#if HC_ARCH_BITS == 32
+typedef int32_t RTHCINTPTR;
+#elif HC_ARCH_BITS == 64
+typedef int64_t RTHCINTPTR;
+#elif HC_ARCH_BITS == 16
+typedef int16_t RTHCINTPTR;
+#else
+# error Unsupported HC_ARCH_BITS value.
+#endif
+/** Pointer to signed integer which can contain a HC pointer. */
+typedef RTHCINTPTR *PRTHCINTPTR;
+/** Pointer to const signed integer which can contain a HC pointer. */
+typedef const RTHCINTPTR *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
+typedef int32_t RTR3INTPTR;
+#elif R3_ARCH_BITS == 64
+typedef int64_t RTR3INTPTR;
+#elif R3_ARCH_BITS == 16
+typedef int16_t RTR3INTPTR;
+#else
+# error Unsupported R3_ARCH_BITS value.
+#endif
+/** Pointer to signed integer which can contain a HC ring-3 pointer. */
+typedef RTR3INTPTR *PRTR3INTPTR;
+/** Pointer to const signed integer which can contain a HC ring-3 pointer. */
+typedef const RTR3INTPTR *PCRTR3INTPTR;
+/** Max RTR3INTPTR value. */
+#if R3_ARCH_BITS == 32
+# define RTR3INTPTR_MAX INT32_MAX
+#elif R3_ARCH_BITS == 64
+# define RTR3INTPTR_MAX INT64_MAX
+#else
+# define RTR3INTPTR_MAX INT16_MAX
+#endif
+/** Min RTR3INTPTR value. */
+#if R3_ARCH_BITS == 32
+# define RTR3INTPTR_MIN INT32_MIN
+#elif R3_ARCH_BITS == 64
+# define RTR3INTPTR_MIN INT64_MIN
+#else
+# define RTR3INTPTR_MIN INT16_MIN
+#endif
+
+/** Signed integer which can contain a HC ring-0 pointer. */
+#if R0_ARCH_BITS == 32
+typedef int32_t RTR0INTPTR;
+#elif R0_ARCH_BITS == 64
+typedef int64_t RTR0INTPTR;
+#elif R0_ARCH_BITS == 16
+typedef int16_t RTR0INTPTR;
+#else
+# error Unsupported R0_ARCH_BITS value.
+#endif
+/** Pointer to signed integer which can contain a HC ring-0 pointer. */
+typedef RTR0INTPTR *PRTR0INTPTR;
+/** Pointer to const signed integer which can contain a HC ring-0 pointer. */
+typedef const RTR0INTPTR *PCRTR0INTPTR;
+/** Max RTR0INTPTR value. */
+#if R0_ARCH_BITS == 32
+# define RTR0INTPTR_MAX INT32_MAX
+#elif R0_ARCH_BITS == 64
+# define RTR0INTPTR_MAX INT64_MAX
+#else
+# define RTR0INTPTR_MAX INT16_MAX
+#endif
+/** Min RTHCINTPTR value. */
+#if R0_ARCH_BITS == 32
+# define RTR0INTPTR_MIN INT32_MIN
+#elif R0_ARCH_BITS == 64
+# define RTR0INTPTR_MIN INT64_MIN
+#else
+# define RTR0INTPTR_MIN INT16_MIN
+#endif
+
+
+/** Unsigned integer which can contain a HC pointer. */
+#if HC_ARCH_BITS == 32
+typedef uint32_t RTHCUINTPTR;
+#elif HC_ARCH_BITS == 64
+typedef uint64_t RTHCUINTPTR;
+#elif HC_ARCH_BITS == 16
+typedef uint16_t RTHCUINTPTR;
+#else
+# error Unsupported HC_ARCH_BITS value.
+#endif
+/** Pointer to unsigned integer which can contain a HC pointer. */
+typedef RTHCUINTPTR *PRTHCUINTPTR;
+/** Pointer to unsigned integer which can contain a HC pointer. */
+typedef const RTHCUINTPTR *PCRTHCUINTPTR;
+/** Max RTHCUINTTPR value. */
+#if HC_ARCH_BITS == 32
+# define RTHCUINTPTR_MAX UINT32_MAX
+#elif HC_ARCH_BITS == 64
+# define RTHCUINTPTR_MAX UINT64_MAX
+#else
+# define RTHCUINTPTR_MAX UINT16_MAX
+#endif
+
+/** Unsigned integer which can contain a HC ring-3 pointer. */
+#if R3_ARCH_BITS == 32
+typedef uint32_t RTR3UINTPTR;
+#elif R3_ARCH_BITS == 64
+typedef uint64_t RTR3UINTPTR;
+#elif R3_ARCH_BITS == 16
+typedef uint16_t RTR3UINTPTR;
+#else
+# error Unsupported R3_ARCH_BITS value.
+#endif
+/** Pointer to unsigned integer which can contain a HC ring-3 pointer. */
+typedef RTR3UINTPTR *PRTR3UINTPTR;
+/** Pointer to unsigned integer which can contain a HC ring-3 pointer. */
+typedef const RTR3UINTPTR *PCRTR3UINTPTR;
+/** Max RTHCUINTTPR value. */
+#if R3_ARCH_BITS == 32
+# define RTR3UINTPTR_MAX UINT32_MAX
+#elif R3_ARCH_BITS == 64
+# define RTR3UINTPTR_MAX UINT64_MAX
+#else
+# define RTR3UINTPTR_MAX UINT16_MAX
+#endif
+
+/** Unsigned integer which can contain a HC ring-0 pointer. */
+#if R0_ARCH_BITS == 32
+typedef uint32_t RTR0UINTPTR;
+#elif R0_ARCH_BITS == 64
+typedef uint64_t RTR0UINTPTR;
+#elif R0_ARCH_BITS == 16
+typedef uint16_t RTR0UINTPTR;
+#else
+# error Unsupported R0_ARCH_BITS value.
+#endif
+/** Pointer to unsigned integer which can contain a HC ring-0 pointer. */
+typedef RTR0UINTPTR *PRTR0UINTPTR;
+/** Pointer to unsigned integer which can contain a HC ring-0 pointer. */
+typedef const RTR0UINTPTR *PCRTR0UINTPTR;
+/** Max RTR0UINTTPR value. */
+#if R0_ARCH_BITS == 32
+# define RTR0UINTPTR_MAX UINT32_MAX
+#elif R0_ARCH_BITS == 64
+# define RTR0UINTPTR_MAX UINT64_MAX
+#else
+# define RTR0UINTPTR_MAX UINT16_MAX
+#endif
+
+
+/** Host Physical Memory Address. */
+typedef uint64_t RTHCPHYS;
+/** Pointer to Host Physical Memory Address. */
+typedef RTHCPHYS *PRTHCPHYS;
+/** Pointer to const Host Physical Memory Address. */
+typedef const RTHCPHYS *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. */
+#ifndef IN_RC
+typedef void * RTHCPTR;
+#else
+typedef RTHCUINTPTR RTHCPTR;
+#endif
+/** Pointer to HC pointer. */
+typedef RTHCPTR *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 * RTR3PTR;
+#else
+typedef RTR3UINTPTR RTR3PTR;
+#endif
+/** Pointer to HC ring-3 pointer. */
+typedef RTR3PTR *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 * RTR0PTR;
+#else
+typedef RTR0UINTPTR RTR0PTR;
+#endif
+/** Pointer to HC ring-0 pointer. */
+typedef RTR0PTR *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 *PRTHCUINTREG;
+/** Pointer to a const unsigned integer register in the host context. */
+typedef const RTHCUINTREG *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 *PRTR3UINTREG;
+/** Pointer to a const unsigned integer register in the host ring-3 context. */
+typedef const RTR3UINTREG *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 *PRTR0UINTREG;
+/** Pointer to a const unsigned integer register in the host ring-3 context. */
+typedef const RTR0UINTREG *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 *PRTGCINT;
+/** Pointer to const natural signed integer in GC.
+ * @deprecated silly type. */
+typedef const RTGCINT *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 *PRTGCUINT;
+/** Pointer to const natural unsigned integer in GC.
+ * @deprecated silly type. */
+typedef const RTGCUINT *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 *PRTGCINTPTR;
+/** Pointer to const signed integer which can contain a GC pointer. */
+typedef const RTGCINTPTR *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 *PRTGCUINTPTR;
+/** Pointer to unsigned integer which can contain a GC pointer. */
+typedef const RTGCUINTPTR *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 *PRTGCUINTPTR32;
+/** Pointer to unsigned integer which can contain a 32 bits GC pointer. */
+typedef const RTGCUINTPTR32 *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 *PRTGCUINTPTR64;
+/** Pointer to unsigned integer which can contain a 32 bits GC pointer. */
+typedef const RTGCUINTPTR64 *PCRTGCUINTPTR64;
+
+/** Guest Physical Memory Address.*/
+typedef uint64_t RTGCPHYS;
+/** Pointer to Guest Physical Memory Address. */
+typedef RTGCPHYS *PRTGCPHYS;
+/** Pointer to const Guest Physical Memory Address. */
+typedef const RTGCPHYS *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 *PRTGCPHYS32;
+/** Pointer to const Guest Physical Memory Address. */
+typedef const RTGCPHYS32 *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 *PRTGCPHYS64;
+/** Pointer to const Guest Physical Memory Address. */
+typedef const RTGCPHYS64 *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 *PRTGCPTR32;
+/** Pointer to a const guest context pointer. */
+typedef const RTGCPTR32 *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 *PRTGCPTR64;
+/** Pointer to a const guest context pointer. */
+typedef const RTGCPTR64 *PCRTGCPTR64;
+/** @def NIL_RTGCPTR64
+ * NIL GC pointer.
+ */
+#define NIL_RTGCPTR64 ((RTGCPTR64)0)
+
+/** Guest context pointer.
+ * Keep in mind that this type is an unsigned integer in
+ * HC and void pointer in GC.
+ */
+#if GC_ARCH_BITS == 64
+typedef RTGCPTR64 RTGCPTR;
+/** Pointer to a guest context pointer. */
+typedef PRTGCPTR64 PRTGCPTR;
+/** Pointer to a const guest context pointer. */
+typedef PCRTGCPTR64 PCRTGCPTR;
+/** @def NIL_RTGCPTR
+ * NIL GC pointer.
+ */
+# define NIL_RTGCPTR NIL_RTGCPTR64
+/** Max RTGCPTR value. */
+# define RTGCPTR_MAX UINT64_MAX
+#elif GC_ARCH_BITS == 32
+typedef RTGCPTR32 RTGCPTR;
+/** Pointer to a guest context pointer. */
+typedef PRTGCPTR32 PRTGCPTR;
+/** Pointer to a const guest context pointer. */
+typedef PCRTGCPTR32 PCRTGCPTR;
+/** @def NIL_RTGCPTR
+ * NIL GC pointer.
+ */
+# define NIL_RTGCPTR NIL_RTGCPTR32
+/** Max RTGCPTR value. */
+# 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 *PRTGCUINTREG32;
+/** Pointer to a const unsigned integer register in the guest context. */
+typedef const RTGCUINTREG32 *PCRTGCUINTREG32;
+
+typedef uint64_t RTGCUINTREG64;
+/** Pointer to an unsigned integer register in the guest context. */
+typedef RTGCUINTREG64 *PRTGCUINTREG64;
+/** Pointer to a const unsigned integer register in the guest context. */
+typedef const RTGCUINTREG64 *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 *PRTGCUINTREG;
+/** Pointer to a const unsigned integer register in the guest context. */
+typedef const RTGCUINTREG *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 * RTRCPTR;
+#else
+typedef uint32_t RTRCPTR;
+#endif
+/** Pointer to a raw mode context pointer. */
+typedef RTRCPTR *PRTRCPTR;
+/** Pointer to a const raw mode context pointer. */
+typedef const RTRCPTR *PCRTRCPTR;
+/** @def NIL_RTGCPTR
+ * NIL RC pointer.
+ */
+#ifndef IN_RC
+# define NIL_RTRCPTR ((RTRCPTR)0)
+#else
+# define NIL_RTRCPTR (NULL)
+#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)
+
+/** @} */
+
+
+/** @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 *PRTCCPHYS;
+/** Pointer to const Current Context Physical Memory Address. */
+typedef const RTCCPHYS *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 *PRTCCUINTREG;
+/** Pointer to a const unsigned integer register in the current context. */
+typedef RTCCUINTREG const *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 *PRTCCINTREG;
+/** Pointer to a const signed integer register in the current context. */
+typedef RTCCINTREG const *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 *PRTCCUINTXREG;
+/** Pointer to a const unsigned integer register in the current context. */
+typedef RTCCUINTREG const *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 *PRTCCINTXREG;
+/** Pointer to a const signed integer extended register in the current
+ * context. */
+typedef RTCCINTXREG const *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. */
+#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"
+#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
+#endif
+/** @} */
+
+
+
+/** Pointer to a big integer number. */
+typedef struct RTBIGNUM *PRTBIGNUM;
+/** Pointer to a const big integer number. */
+typedef struct RTBIGNUM const *PCRTBIGNUM;
+
+
+/** Pointer to a critical section. */
+typedef struct RTCRITSECT *PRTCRITSECT;
+/** Pointer to a const critical section. */
+typedef const struct RTCRITSECT *PCRTCRITSECT;
+
+/** Pointer to a read/write critical section. */
+typedef struct RTCRITSECTRW *PRTCRITSECTRW;
+/** Pointer to a const read/write critical section. */
+typedef const struct RTCRITSECTRW *PCRTCRITSECTRW;
+
+
+/** Condition variable handle. */
+typedef R3PTRTYPE(struct RTCONDVARINTERNAL *) RTCONDVAR;
+/** Pointer to a condition variable handle. */
+typedef RTCONDVAR *PRTCONDVAR;
+/** Nil condition variable handle. */
+#define NIL_RTCONDVAR 0
+
+/** Cryptographic (certificate) store handle. */
+typedef R3R0PTRTYPE(struct RTCRSTOREINT *) RTCRSTORE;
+/** Pointer to a Cryptographic (certificate) store handle. */
+typedef RTCRSTORE *PRTCRSTORE;
+/** Nil Cryptographic (certificate) store handle. */
+#define NIL_RTCRSTORE 0
+
+/** Pointer to a const (store) certificate context. */
+typedef struct RTCRCERTCTX const *PCRTCRCERTCTX;
+
+/** Cryptographic message digest handle. */
+typedef R3R0PTRTYPE(struct RTCRDIGESTINT *) RTCRDIGEST;
+/** Pointer to a cryptographic message digest handle. */
+typedef RTCRDIGEST *PRTCRDIGEST;
+/** NIL cryptographic message digest handle. */
+#define NIL_RTCRDIGEST (0)
+
+/** Public key encryption schema handle. */
+typedef R3R0PTRTYPE(struct RTCRPKIXENCRYPTIONINT *) RTCRPKIXENCRYPTION;
+/** Pointer to a public key encryption schema handle. */
+typedef RTCRPKIXENCRYPTION *PRTCRPKIXENCRYPTION;
+/** NIL public key encryption schema handle */
+#define NIL_RTCRPKIXENCRYPTION (0)
+
+/** Public key signature schema handle. */
+typedef R3R0PTRTYPE(struct RTCRPKIXSIGNATUREINT *) RTCRPKIXSIGNATURE;
+/** Pointer to a public key signature schema handle. */
+typedef RTCRPKIXSIGNATURE *PRTCRPKIXSIGNATURE;
+/** NIL public key signature schema handle */
+#define NIL_RTCRPKIXSIGNATURE (0)
+
+/** X.509 certificate paths builder & validator handle. */
+typedef R3R0PTRTYPE(struct RTCRX509CERTPATHSINT *) RTCRX509CERTPATHS;
+/** Pointer to a certificate paths builder & validator handle. */
+typedef RTCRX509CERTPATHS *PRTCRX509CERTPATHS;
+/** Nil certificate paths builder & validator handle. */
+#define NIL_RTCRX509CERTPATHS 0
+
+/** File handle. */
+typedef R3R0PTRTYPE(struct RTFILEINT *) RTFILE;
+/** Pointer to file handle. */
+typedef RTFILE *PRTFILE;
+/** Nil file handle. */
+#define NIL_RTFILE ((RTFILE)~(RTHCINTPTR)0)
+
+/** Async I/O request handle. */
+typedef R3PTRTYPE(struct RTFILEAIOREQINTERNAL *) RTFILEAIOREQ;
+/** Pointer to an async I/O request handle. */
+typedef RTFILEAIOREQ *PRTFILEAIOREQ;
+/** Nil request handle. */
+#define NIL_RTFILEAIOREQ 0
+
+/** Async I/O completion context handle. */
+typedef R3PTRTYPE(struct RTFILEAIOCTXINTERNAL *) RTFILEAIOCTX;
+/** Pointer to an async I/O completion context handle. */
+typedef RTFILEAIOCTX *PRTFILEAIOCTX;
+/** Nil context handle. */
+#define NIL_RTFILEAIOCTX 0
+
+/** Loader module handle. */
+typedef R3R0PTRTYPE(struct RTLDRMODINTERNAL *) RTLDRMOD;
+/** Pointer to a loader module handle. */
+typedef RTLDRMOD *PRTLDRMOD;
+/** Nil loader module handle. */
+#define NIL_RTLDRMOD 0
+
+/** Lock validator class handle. */
+typedef R3R0PTRTYPE(struct RTLOCKVALCLASSINT *) RTLOCKVALCLASS;
+/** Pointer to a lock validator class handle. */
+typedef RTLOCKVALCLASS *PRTLOCKVALCLASS;
+/** Nil lock validator class handle. */
+#define NIL_RTLOCKVALCLASS ((RTLOCKVALCLASS)0)
+
+/** Ring-0 memory object handle. */
+typedef R0PTRTYPE(struct RTR0MEMOBJINTERNAL *) RTR0MEMOBJ;
+/** Pointer to a Ring-0 memory object handle. */
+typedef RTR0MEMOBJ *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 *PRTNATIVETHREAD;
+/** Nil native thread handle. */
+#define NIL_RTNATIVETHREAD (~(RTNATIVETHREAD)0)
+
+/** Pipe handle. */
+typedef R3R0PTRTYPE(struct RTPIPEINTERNAL *) RTPIPE;
+/** Pointer to a pipe handle. */
+typedef RTPIPE *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 *) RTPOLLSET;
+/** Pointer to a poll set handle. */
+typedef RTPOLLSET *PRTPOLLSET;
+/** Nil poll set handle handle. */
+#define NIL_RTPOLLSET ((RTPOLLSET)0)
+
+/** Process identifier. */
+typedef uint32_t RTPROCESS;
+/** Pointer to a process identifier. */
+typedef RTPROCESS *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 *PRTR0PROCESS;
+/** Nil ring-0 process handle. */
+#define NIL_RTR0PROCESS (~(RTR0PROCESS)0)
+
+/** @typedef RTSEMEVENT
+ * Event Semaphore handle. */
+typedef R3R0PTRTYPE(struct RTSEMEVENTINTERNAL *) RTSEMEVENT;
+/** Pointer to an event semaphore handle. */
+typedef RTSEMEVENT *PRTSEMEVENT;
+/** Nil event semaphore handle. */
+#define NIL_RTSEMEVENT 0
+
+/** @typedef RTSEMEVENTMULTI
+ * Event Multiple Release Semaphore handle. */
+typedef R3R0PTRTYPE(struct RTSEMEVENTMULTIINTERNAL *) RTSEMEVENTMULTI;
+/** Pointer to an event multiple release semaphore handle. */
+typedef RTSEMEVENTMULTI *PRTSEMEVENTMULTI;
+/** Nil multiple release event semaphore handle. */
+#define NIL_RTSEMEVENTMULTI 0
+
+/** @typedef RTSEMFASTMUTEX
+ * Fast mutex Semaphore handle. */
+typedef R3R0PTRTYPE(struct RTSEMFASTMUTEXINTERNAL *) RTSEMFASTMUTEX;
+/** Pointer to a fast mutex semaphore handle. */
+typedef RTSEMFASTMUTEX *PRTSEMFASTMUTEX;
+/** Nil fast mutex semaphore handle. */
+#define NIL_RTSEMFASTMUTEX 0
+
+/** @typedef RTSEMMUTEX
+ * Mutex Semaphore handle. */
+typedef R3R0PTRTYPE(struct RTSEMMUTEXINTERNAL *) RTSEMMUTEX;
+/** Pointer to a mutex semaphore handle. */
+typedef RTSEMMUTEX *PRTSEMMUTEX;
+/** Nil mutex semaphore handle. */
+#define NIL_RTSEMMUTEX 0
+
+/** @typedef RTSEMSPINMUTEX
+ * Spinning mutex Semaphore handle. */
+typedef R3R0PTRTYPE(struct RTSEMSPINMUTEXINTERNAL *) RTSEMSPINMUTEX;
+/** Pointer to a spinning mutex semaphore handle. */
+typedef RTSEMSPINMUTEX *PRTSEMSPINMUTEX;
+/** Nil spinning mutex semaphore handle. */
+#define NIL_RTSEMSPINMUTEX 0
+
+/** @typedef RTSEMRW
+ * Read/Write Semaphore handle. */
+typedef R3R0PTRTYPE(struct RTSEMRWINTERNAL *) RTSEMRW;
+/** Pointer to a read/write semaphore handle. */
+typedef RTSEMRW *PRTSEMRW;
+/** Nil read/write semaphore handle. */
+#define NIL_RTSEMRW 0
+
+/** @typedef RTSEMXROADS
+ * Crossroads semaphore handle. */
+typedef R3R0PTRTYPE(struct RTSEMXROADSINTERNAL *) RTSEMXROADS;
+/** Pointer to a crossroads semaphore handle. */
+typedef RTSEMXROADS *PRTSEMXROADS;
+/** Nil crossroads semaphore handle. */
+#define NIL_RTSEMXROADS ((RTSEMXROADS)0)
+
+/** Spinlock handle. */
+typedef R3R0PTRTYPE(struct RTSPINLOCKINTERNAL *) RTSPINLOCK;
+/** Pointer to a spinlock handle. */
+typedef RTSPINLOCK *PRTSPINLOCK;
+/** Nil spinlock handle. */
+#define NIL_RTSPINLOCK 0
+
+/** Socket handle. */
+typedef R3R0PTRTYPE(struct RTSOCKETINT *) RTSOCKET;
+/** Pointer to socket handle. */
+typedef RTSOCKET *PRTSOCKET;
+/** Nil socket handle. */
+#define NIL_RTSOCKET ((RTSOCKET)0)
+
+/** Pointer to a RTTCPSERVER handle. */
+typedef struct RTTCPSERVER *PRTTCPSERVER;
+/** Pointer to a RTTCPSERVER handle. */
+typedef PRTTCPSERVER *PPRTTCPSERVER;
+/** Nil RTTCPSERVER handle. */
+#define NIL_RTTCPSERVER ((PRTTCPSERVER)0)
+
+/** Pointer to a RTUDPSERVER handle. */
+typedef struct RTUDPSERVER *PRTUDPSERVER;
+/** Pointer to a RTUDPSERVER handle. */
+typedef PRTUDPSERVER *PPRTUDPSERVER;
+/** Nil RTUDPSERVER handle. */
+#define NIL_RTUDPSERVER ((PRTUDPSERVER)0)
+
+/** Thread handle.*/
+typedef R3R0PTRTYPE(struct RTTHREADINT *) RTTHREAD;
+/** Pointer to thread handle. */
+typedef RTTHREAD *PRTTHREAD;
+/** Nil thread handle. */
+#define NIL_RTTHREAD 0
+
+/** Thread context switching hook handle. */
+typedef R0PTRTYPE(struct RTTHREADCTXHOOKINT *) RTTHREADCTXHOOK;
+/** Pointer to Thread context switching hook handle. */
+typedef RTTHREADCTXHOOK *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 *PRTTLS;
+/** Pointer to a const TLS index. */
+typedef RTTLS const *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 *RTTRACEBUF;
+/** Pointer to a trace buffer handle. */
+typedef RTTRACEBUF *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 *) RTHEAPSIMPLE;
+/** Pointer to a handle to a simple heap. */
+typedef RTHEAPSIMPLE *PRTHEAPSIMPLE;
+/** NIL simple heap handle. */
+#define NIL_RTHEAPSIMPLE ((RTHEAPSIMPLE)0)
+
+/** Handle to an offset based heap. */
+typedef R3R0PTRTYPE(struct RTHEAPOFFSETINTERNAL *) RTHEAPOFFSET;
+/** Pointer to a handle to an offset based heap. */
+typedef RTHEAPOFFSET *PRTHEAPOFFSET;
+/** NIL offset based heap handle. */
+#define NIL_RTHEAPOFFSET ((RTHEAPOFFSET)0)
+
+/** Handle to an environment block. */
+typedef R3PTRTYPE(struct RTENVINTERNAL *) RTENV;
+/** Pointer to a handle to an environment block. */
+typedef RTENV *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 *PRTCPUID;
+/** Pointer to a const CPU identifier. */
+typedef RTCPUID const *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 multiple of 64 (see RTCPUSET). */
+#if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)
+# define RTCPUSET_MAX_CPUS 256
+#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 *PRTCPUSET;
+/** Pointer to a const CPU set. */
+typedef RTCPUSET const *PCRTCPUSET;
+
+/** A handle table handle. */
+typedef R3R0PTRTYPE(struct RTHANDLETABLEINT *) RTHANDLETABLE;
+/** A pointer to a handle table handle. */
+typedef RTHANDLETABLE *PRTHANDLETABLE;
+/** @def NIL_RTHANDLETABLE
+ * NIL handle table handle. */
+#define NIL_RTHANDLETABLE ((RTHANDLETABLE)0)
+
+/** A handle to a low resolution timer. */
+typedef R3R0PTRTYPE(struct RTTIMERLRINT *) RTTIMERLR;
+/** A pointer to a low resolution timer handle. */
+typedef RTTIMERLR *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 *) RTRAND;
+/** Pointer to a random number generator handle. */
+typedef RTRAND *PRTRAND;
+/** NIL random number generator handle value. */
+#define NIL_RTRAND ((RTRAND)0)
+
+/** Debug address space handle. */
+typedef R3R0PTRTYPE(struct RTDBGASINT *) RTDBGAS;
+/** Pointer to a debug address space handle. */
+typedef RTDBGAS *PRTDBGAS;
+/** NIL debug address space handle. */
+#define NIL_RTDBGAS ((RTDBGAS)0)
+
+/** Debug module handle. */
+typedef R3R0PTRTYPE(struct RTDBGMODINT *) RTDBGMOD;
+/** Pointer to a debug module handle. */
+typedef RTDBGMOD *PRTDBGMOD;
+/** NIL debug module handle. */
+#define NIL_RTDBGMOD ((RTDBGMOD)0)
+
+/** Manifest handle. */
+typedef struct RTMANIFESTINT *RTMANIFEST;
+/** Pointer to a manifest handle. */
+typedef RTMANIFEST *PRTMANIFEST;
+/** NIL manifest handle. */
+#define NIL_RTMANIFEST ((RTMANIFEST)~(uintptr_t)0)
+
+/** Memory pool handle. */
+typedef R3R0PTRTYPE(struct RTMEMPOOLINT *) RTMEMPOOL;
+/** Pointer to a memory pool handle. */
+typedef RTMEMPOOL *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 *) RTSTRCACHE;
+/** Pointer to a string cache handle. */
+typedef RTSTRCACHE *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 *RTVFS;
+/** Pointer to a VFS handle. */
+typedef RTVFS *PRTVFS;
+/** A NIL VFS handle. */
+#define NIL_RTVFS ((RTVFS)~(uintptr_t)0)
+
+/** Virtual Filesystem base object handle. */
+typedef struct RTVFSOBJINTERNAL *RTVFSOBJ;
+/** Pointer to a VFS base object handle. */
+typedef RTVFSOBJ *PRTVFSOBJ;
+/** A NIL VFS base object handle. */
+#define NIL_RTVFSOBJ ((RTVFSOBJ)~(uintptr_t)0)
+
+/** Virtual Filesystem directory handle. */
+typedef struct RTVFSDIRINTERNAL *RTVFSDIR;
+/** Pointer to a VFS directory handle. */
+typedef RTVFSDIR *PRTVFSDIR;
+/** A NIL VFS directory handle. */
+#define NIL_RTVFSDIR ((RTVFSDIR)~(uintptr_t)0)
+
+/** Virtual Filesystem filesystem stream handle. */
+typedef struct RTVFSFSSTREAMINTERNAL *RTVFSFSSTREAM;
+/** Pointer to a VFS filesystem stream handle. */
+typedef RTVFSFSSTREAM *PRTVFSFSSTREAM;
+/** A NIL VFS filesystem stream handle. */
+#define NIL_RTVFSFSSTREAM ((RTVFSFSSTREAM)~(uintptr_t)0)
+
+/** Virtual Filesystem I/O stream handle. */
+typedef struct RTVFSIOSTREAMINTERNAL *RTVFSIOSTREAM;
+/** Pointer to a VFS I/O stream handle. */
+typedef RTVFSIOSTREAM *PRTVFSIOSTREAM;
+/** A NIL VFS I/O stream handle. */
+#define NIL_RTVFSIOSTREAM ((RTVFSIOSTREAM)~(uintptr_t)0)
+
+/** Virtual Filesystem file handle. */
+typedef struct RTVFSFILEINTERNAL *RTVFSFILE;
+/** Pointer to a VFS file handle. */
+typedef RTVFSFILE *PRTVFSFILE;
+/** A NIL VFS file handle. */
+#define NIL_RTVFSFILE ((RTVFSFILE)~(uintptr_t)0)
+
+/** Virtual Filesystem symbolic link handle. */
+typedef struct RTVFSSYMLINKINTERNAL *RTVFSSYMLINK;
+/** Pointer to a VFS symbolic link handle. */
+typedef RTVFSSYMLINK *PRTVFSSYMLINK;
+/** A NIL VFS symbolic link handle. */
+#define NIL_RTVFSSYMLINK ((RTVFSSYMLINK)~(uintptr_t)0)
+
+/** Async I/O manager handle. */
+typedef struct RTAIOMGRINT *RTAIOMGR;
+/** Pointer to a async I/O manager handle. */
+typedef RTAIOMGR *PRTAIOMGR;
+/** A NIL async I/O manager handle. */
+#define NIL_RTAIOMGR ((RTAIOMGR)~(uintptr_t)0)
+
+/** Async I/O manager file handle. */
+typedef struct RTAIOMGRFILEINT *RTAIOMGRFILE;
+/** Pointer to a async I/O manager file handle. */
+typedef RTAIOMGRFILE *PRTAIOMGRFILE;
+/** A NIL async I/O manager file handle. */
+#define NIL_RTAIOMGRFILE ((RTAIOMGRFILE)~(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 *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 *PRTHANDLEUNION;
+/** Pointer to a const handle union. */
+typedef RTHANDLEUNION const *PCRTHANDLEUNION;
+
+/**
+ * Generic handle.
+ */
+typedef struct RTHANDLE
+{
+ /** The handle type. */
+ RTHANDLETYPE enmType;
+ /** The handle value. */
+ RTHANDLEUNION u;
+} RTHANDLE;
+/** Pointer to a generic handle. */
+typedef RTHANDLE *PRTHANDLE;
+/** Pointer to a const generic handle. */
+typedef RTHANDLE const *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 *PRTERRINFO;
+/** Pointer to a const error info structure. */
+typedef RTERRINFO const *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 *PRTERRINFOSTATIC;
+/** Pointer to a const static error info buffer. */
+typedef RTERRINFOSTATIC const *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 *PRTUUID;
+/** Pointer to readonly UUID data. */
+typedef const RTUUID *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 *PRTZIPCOMP;
+/** Decompressor handle. */
+typedef struct RTZIPDECOMP *PRTZIPDECOMP;
+
+
+/**
+ * Unicode Code Point.
+ */
+typedef uint32_t RTUNICP;
+/** Pointer to an Unicode Code Point. */
+typedef RTUNICP *PRTUNICP;
+/** Pointer to an Unicode Code Point. */
+typedef const RTUNICP *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 *PRTUTF16;
+/** Pointer to a const UTF-16 character. */
+typedef const RTUTF16 *PCRTUTF16;
+
+
+/**
+ * String tuple to go with the RT_STR_TUPLE macro.
+ */
+typedef struct RTSTRTUPLE
+{
+ /** The string. */
+ const char *psz;
+ /** The string length. */
+ size_t cch;
+} RTSTRTUPLE;
+/** Pointer to a string tuple. */
+typedef RTSTRTUPLE *PRTSTRTUPLE;
+/** Pointer to a const string tuple. */
+typedef RTSTRTUPLE const *PCRTSTRTUPLE;
+
+/**
+ * Wait for ever if we have to.
+ */
+#define RT_INDEFINITE_WAIT (~0U)
+
+
+/**
+ * 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 DECLCALLBACK(int) FNRTPROGRESS(unsigned uPrecentage, 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 DECLCALLBACK(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 *PRTPOINT;
+/** Pointer to a const point. */
+typedef const RTPOINT *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 *PRTRECT;
+/** Pointer to a const double point rectangle. */
+typedef const RTRECT *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 *PRTRECT2;
+/** Pointer to a const point + size rectangle. */
+typedef const RTRECT2 *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 *PRTRECTSIZE;
+/** Pointer to a const rectangle size. */
+typedef const RTRECTSIZE *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 *PRTMAC;
+/** Pointer to a readonly MAC address. */
+typedef const RTMAC *PCRTMAC;
+
+
+/** Pointer to a lock validator record.
+ * The structure definition is found in iprt/lockvalidator.h. */
+typedef struct RTLOCKVALRECEXCL *PRTLOCKVALRECEXCL;
+/** Pointer to a record of one ownership share.
+ * The structure definition is found in iprt/lockvalidator.h. */
+typedef struct RTLOCKVALRECSHRD *PRTLOCKVALRECSHRD;
+/** Pointer to a lock validator source position.
+ * The structure definition is found in iprt/lockvalidator.h. */
+typedef struct RTLOCKVALSRCPOS *PRTLOCKVALSRCPOS;
+/** Pointer to a const lock validator source position.
+ * The structure definition is found in iprt/lockvalidator.h. */
+typedef struct RTLOCKVALSRCPOS const *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,
+ /** 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 *PRTRANGE;
+/** Pointer to a readonly range descriptor. */
+typedef const RTRANGE *PCRTRANGE;
+
+
+/**
+ * Generic pointer union.
+ */
+typedef union RTPTRUNION
+{
+ /** Pointer into the void. */
+ void *pv;
+ /** As a signed integer. */
+ intptr_t i;
+ /** As an unsigned integer. */
+ intptr_t u;
+ /** Pointer to char value. */
+ char *pch;
+ /** Pointer to char value. */
+ unsigned char *puch;
+ /** Pointer to a int value. */
+ int *pi;
+ /** Pointer to a unsigned int value. */
+ unsigned int *pu;
+ /** Pointer to a long value. */
+ long *pl;
+ /** Pointer to a long value. */
+ unsigned long *pul;
+ /** Pointer to a 8-bit unsigned value. */
+ uint8_t *pu8;
+ /** Pointer to a 16-bit unsigned value. */
+ uint16_t *pu16;
+ /** Pointer to a 32-bit unsigned value. */
+ uint32_t *pu32;
+ /** Pointer to a 64-bit unsigned value. */
+ uint64_t *pu64;
+ /** Pointer to a UTF-16 character. */
+ PRTUTF16 pwc;
+ /** Pointer to a UUID character. */
+ PRTUUID pUuid;
+} RTPTRUNION;
+/** Pointer to a pointer union. */
+typedef RTPTRUNION *PRTPTRUNION;
+
+/**
+ * Generic const pointer union.
+ */
+typedef union RTCPTRUNION
+{
+ /** Pointer into the void. */
+ void const *pv;
+ /** As a signed integer. */
+ intptr_t i;
+ /** As an unsigned integer. */
+ intptr_t u;
+ /** Pointer to char value. */
+ char const *pch;
+ /** Pointer to char value. */
+ unsigned char const *puch;
+ /** Pointer to a int value. */
+ int const *pi;
+ /** Pointer to a unsigned int value. */
+ unsigned int const *pu;
+ /** Pointer to a long value. */
+ long const *pl;
+ /** Pointer to a long value. */
+ unsigned long const *pul;
+ /** Pointer to a 8-bit unsigned value. */
+ uint8_t const *pu8;
+ /** Pointer to a 16-bit unsigned value. */
+ uint16_t const *pu16;
+ /** Pointer to a 32-bit unsigned value. */
+ uint32_t const *pu32;
+ /** Pointer to a 64-bit unsigned value. */
+ uint64_t const *pu64;
+ /** Pointer to a UTF-16 character. */
+ PCRTUTF16 pwc;
+ /** Pointer to a UUID character. */
+ PCRTUUID pUuid;
+} RTCPTRUNION;
+/** Pointer to a const pointer union. */
+typedef RTCPTRUNION *PRTCPTRUNION;
+
+/**
+ * Generic volatile pointer union.
+ */
+typedef union RTVPTRUNION
+{
+ /** Pointer into the void. */
+ void volatile *pv;
+ /** As a signed integer. */
+ intptr_t i;
+ /** As an unsigned integer. */
+ intptr_t u;
+ /** Pointer to char value. */
+ char volatile *pch;
+ /** Pointer to char value. */
+ unsigned char volatile *puch;
+ /** Pointer to a int value. */
+ int volatile *pi;
+ /** Pointer to a unsigned int value. */
+ unsigned int volatile *pu;
+ /** Pointer to a long value. */
+ long volatile *pl;
+ /** Pointer to a long value. */
+ unsigned long volatile *pul;
+ /** Pointer to a 8-bit unsigned value. */
+ uint8_t volatile *pu8;
+ /** Pointer to a 16-bit unsigned value. */
+ uint16_t volatile *pu16;
+ /** Pointer to a 32-bit unsigned value. */
+ uint32_t volatile *pu32;
+ /** Pointer to a 64-bit unsigned value. */
+ uint64_t volatile *pu64;
+ /** Pointer to a UTF-16 character. */
+ RTUTF16 volatile *pwc;
+ /** Pointer to a UUID character. */
+ RTUUID volatile *pUuid;
+} RTVPTRUNION;
+/** Pointer to a const pointer union. */
+typedef RTVPTRUNION *PRTVPTRUNION;
+
+/**
+ * Generic const volatile pointer union.
+ */
+typedef union RTCVPTRUNION
+{
+ /** Pointer into the void. */
+ void const volatile *pv;
+ /** As a signed integer. */
+ intptr_t i;
+ /** As an unsigned integer. */
+ intptr_t u;
+ /** Pointer to char value. */
+ char const volatile *pch;
+ /** Pointer to char value. */
+ unsigned char const volatile *puch;
+ /** Pointer to a int value. */
+ int const volatile *pi;
+ /** Pointer to a unsigned int value. */
+ unsigned int const volatile *pu;
+ /** Pointer to a long value. */
+ long const volatile *pl;
+ /** Pointer to a long value. */
+ unsigned long const volatile *pul;
+ /** Pointer to a 8-bit unsigned value. */
+ uint8_t const volatile *pu8;
+ /** Pointer to a 16-bit unsigned value. */
+ uint16_t const volatile *pu16;
+ /** Pointer to a 32-bit unsigned value. */
+ uint32_t const volatile *pu32;
+ /** Pointer to a 64-bit unsigned value. */
+ uint64_t const volatile *pu64;
+ /** Pointer to a UTF-16 character. */
+ RTUTF16 const volatile *pwc;
+ /** Pointer to a UUID character. */
+ RTUUID const volatile *pUuid;
+} RTCVPTRUNION;
+/** Pointer to a const pointer union. */
+typedef RTCVPTRUNION *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 */
+/** @} */
+
+#endif
+
--- /dev/null
+/** @file
+ * IPRT - RTUINT64U methods for old 32-bit and 16-bit compilers.
+ */
+
+/*
+ * Copyright (C) 2011-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_uint64_h
+#define ___iprt_uint64_h
+
+#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
+
--- /dev/null
+/** @file
+ * IPRT - Unicode Code Points.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_uni_h
+#define ___iprt_uni_h
+
+/** @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
+
--- /dev/null
+/** @file
+ * IPRT - String Manipulation, UTF-16 encoding.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_utf16_h
+#define ___iprt_utf16_h
+
+#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);
+
+/**
+ * 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.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 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.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, 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.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) RTUtf16CmpUtf8(PCRTUTF16 pwsz1, const char *psz2);
+
+/**
+ * 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 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 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);
+
+
+/**
+ * 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);
+
+/**
+ * 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);
+
+/**
+ * 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-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);
+
+/**
+ * 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);
+
+/**
+ * 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);
+}
+
+/**
+ * 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);
+
+/** @} */
+
+
+RT_C_DECLS_END
+
+/** @} */
+
+#endif
+
--- /dev/null
+/** @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-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_x86_h
+#define ___iprt_x86_h
+
+#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 */
+#ifdef RT_OS_SOLARIS
+# undef CS
+# undef DS
+#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)
+/** 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)
+/** Bit 9 - IF - Interrupt flag - System flag. */
+#define X86_EFL_IF RT_BIT_32(9)
+/** Bit 10 - DF - Direction flag - Control flag. */
+#define X86_EFL_DF RT_BIT_32(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)
+/** Bit 16 - RF - Resume flag - System flag. */
+#define X86_EFL_RF RT_BIT_32(16)
+/** Bit 17 - VM - Virtual 8086 mode - System flag. */
+#define X86_EFL_VM RT_BIT_32(17)
+/** Bit 18 - AC - Alignment check flag - System flag. Works with CR0.AM. */
+#define X86_EFL_AC RT_BIT_32(18)
+/** Bit 19 - VIF - Virtual interrupt flag - System flag. */
+#define X86_EFL_VIF RT_BIT_32(19)
+/** Bit 20 - VIP - Virtual interrupt pending flag - System flag. */
+#define X86_EFL_VIP RT_BIT_32(20)
+/** Bit 21 - ID - CPUID flag - System flag. If this responds to flipping CPUID is supported. */
+#define X86_EFL_ID RT_BIT_32(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)
+/** 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 */
+/** @} */
+
+
+/** @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)
+/** @} */
+
+
+/** @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 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 - DecodeAssist - Indicate decode assist is supported. */
+#define X86_CPUID_SVM_FEATURE_EDX_DECODE_ASSIST 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)
+/** @} */
+
+
+/** @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)
+/** @} */
+
+
+/** @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 Page directory page number. */
+#define X86_CR3_AMD64_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 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 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)
+/** @} */
+
+
+/** @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)
+/** 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 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 - Local 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 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 0U
+/** Break on write only. */
+#define X86_DR7_RW_WO 1U
+/** Break on I/O read/write. This is only defined if CR4.DE is set. */
+#define X86_DR7_RW_IO 2U
+/** Break on read or write (but not instruction fetches). */
+#define X86_DR7_RW_RW 3U
+/** @} */
+
+/** 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 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 0U
+#define X86_DR7_LEN_WORD 1U
+#define X86_DR7_LEN_QWORD 2U /**< AMD64 long mode only. */
+#define X86_DR7_LEN_DWORD 3U
+/** @} */
+
+/** 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
+#define MSR_IA32_FEATURE_CONTROL_LOCK RT_BIT_32(0)
+#define MSR_IA32_FEATURE_CONTROL_SMX_VMXON RT_BIT_32(1)
+#define MSR_IA32_FEATURE_CONTROL_VMXON RT_BIT_32(2)
+
+/** Per-processor TSC adjust MSR. */
+#define MSR_IA32_TSC_ADJUST 0x3B
+
+/** 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
+
+/** 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
+
+/** 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
+
+/** 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
+
+/** Performance counter MSRs. (Intel only) */
+#define MSR_IA32_PERFEVTSEL0 0x186
+#define MSR_IA32_PERFEVTSEL1 0x187
+/** 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
+
+/** 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)
+/** The number (0..3 or 0..15) of the last branch record register on P4 and
+ * related Xeons. */
+#define MSR_P4_LASTBRANCH_TOS UINT32_C(0x000001da)
+/** @name Last branch registers for P4 and Xeon, models 0 thru 2.
+ * @{ */
+#define MSR_P4_LASTBRANCH_0 UINT32_C(0x000001db)
+#define MSR_P4_LASTBRANCH_1 UINT32_C(0x000001dc)
+#define MSR_P4_LASTBRANCH_2 UINT32_C(0x000001dd)
+#define MSR_P4_LASTBRANCH_3 UINT32_C(0x000001de)
+/** @} */
+
+
+#define IA32_MTRR_PHYSBASE0 0x200
+#define IA32_MTRR_PHYSMASK0 0x201
+#define IA32_MTRR_PHYSBASE1 0x202
+#define IA32_MTRR_PHYSMASK1 0x203
+#define IA32_MTRR_PHYSBASE2 0x204
+#define IA32_MTRR_PHYSMASK2 0x205
+#define IA32_MTRR_PHYSBASE3 0x206
+#define IA32_MTRR_PHYSMASK3 0x207
+#define IA32_MTRR_PHYSBASE4 0x208
+#define IA32_MTRR_PHYSMASK4 0x209
+#define IA32_MTRR_PHYSBASE5 0x20a
+#define IA32_MTRR_PHYSMASK5 0x20b
+#define IA32_MTRR_PHYSBASE6 0x20c
+#define IA32_MTRR_PHYSMASK6 0x20d
+#define IA32_MTRR_PHYSBASE7 0x20e
+#define IA32_MTRR_PHYSMASK7 0x20f
+#define IA32_MTRR_PHYSBASE8 0x210
+#define IA32_MTRR_PHYSMASK8 0x211
+#define IA32_MTRR_PHYSBASE9 0x212
+#define IA32_MTRR_PHYSMASK9 0x213
+
+/** Fixed range MTRRs.
+ * @{ */
+#define IA32_MTRR_FIX64K_00000 0x250
+#define IA32_MTRR_FIX16K_80000 0x258
+#define IA32_MTRR_FIX16K_A0000 0x259
+#define IA32_MTRR_FIX4K_C0000 0x268
+#define IA32_MTRR_FIX4K_C8000 0x269
+#define IA32_MTRR_FIX4K_D0000 0x26a
+#define IA32_MTRR_FIX4K_D8000 0x26b
+#define IA32_MTRR_FIX4K_E0000 0x26c
+#define IA32_MTRR_FIX4K_E8000 0x26d
+#define IA32_MTRR_FIX4K_F0000 0x26e
+#define 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_INFO 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 VMX exit controls. */
+#define MSR_IA32_VMX_EXIT_CTLS 0x483
+/** Allowed settings for the VMX 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 the VM-functions controls. */
+#define MSR_IA32_VMX_VMFUNC 0x491
+/** Allowed settings for secondary proc-based VM execution controls */
+#define MSR_IA32_VMX_PROCBASED_CTLS2 0x48B
+/** EPT capabilities. */
+#define MSR_IA32_VMX_EPT_VPID_CAP 0x48C
+/** DS Save Area (R/W). */
+#define MSR_IA32_DS_AREA 0x600
+/** Running Average Power Limit (RAPL) power units. */
+#define MSR_RAPL_POWER_UNIT 0x606
+
+/** 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 0xBFF
+/** 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)
+/** Bit 10 - LMA - Long mode active. (R) */
+#define MSR_K6_EFER_LMA RT_BIT_32(10)
+/** 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)
+/** 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)
+/** 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)
+
+/** @} */
+
+
+/** @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
+
+/**
+ * Check if the given address is canonical.
+ */
+#define X86_IS_CANONICAL(a_u64Addr) ((uint64_t)(a_u64Addr) + UINT64_C(0x800000000000) < UINT64_C(0x1000000000000))
+
+
+/** @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;
+ /** Bit field view. */
+ X86PTEBITS n;
+ /** 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;
+ /** Bit field view. */
+ X86PTEPAEBITS n;
+ /** 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;
+ /** Normal view. */
+ X86PDEBITS n;
+ /** 4MB view (big). */
+ X86PDE4MBITS b;
+ /** 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;
+ /** Normal view. */
+ X86PDEPAEBITS n;
+ /** 2MB page view (big). */
+ X86PDE2MPAEBITS b;
+ /** 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 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;
+ /** Normal view. */
+ X86PDPEBITS n;
+ /** AMD64 view. */
+ X86PDPEAMD64BITS lm;
+ /** AMD64 big view. */
+ X86PDPE1GB b;
+ /** 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;
+ /** Normal view. */
+ X86PML4EBITS n;
+ /** 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
+
+/** @} */
+
+/** @} */
+
+/**
+ * 32-bit protected mode FSTENV image.
+ */
+typedef struct X86FSTENV32P
+{
+ uint16_t FCW;
+ uint16_t padding1;
+ uint16_t FSW;
+ uint16_t padding2;
+ uint16_t FTW;
+ uint16_t padding3;
+ uint32_t FPUIP;
+ uint16_t FPUCS;
+ uint16_t FOP;
+ uint32_t FPUDP;
+ uint16_t FPUDS;
+ uint16_t padding4;
+} X86FSTENV32P;
+/** 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;
+
+/**
+ * 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];
+ /** 128-bit view. (yeah, very helpful) */
+ uint128_t au128[1];
+ /** Confusing nested 128-bit union view (this is what xmm should've been). */
+ RTUINT128U uXmm;
+} 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
+{
+ /** 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];
+ /** 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];
+ /** 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).
+ * @todo verify this...
+ */
+#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 - FOO. */
+ uint32_t FPUOO;
+ /** 0x18 - FOS. */
+ uint32_t FPUOS;
+ /** 0x1c - FPU register. */
+ X86FPUREG regs[8];
+} X86FPUSTATE;
+#pragma pack()
+/** 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)
+/** Exception Flag: Denormalized operand. */
+#define X86_FSW_DE RT_BIT_32(1)
+/** Exception Flag: Zero divide. */
+#define X86_FSW_ZE RT_BIT_32(2)
+/** Exception Flag: Overflow. */
+#define X86_FSW_OE RT_BIT_32(3)
+/** Exception Flag: Underflow. */
+#define X86_FSW_UE RT_BIT_32(4)
+/** Exception Flag: Precision. */
+#define X86_FSW_PE RT_BIT_32(5)
+/** Stack fault. */
+#define X86_FSW_SF RT_BIT_32(6)
+/** Error summary status. */
+#define X86_FSW_ES RT_BIT_32(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(8)
+/** Condition code 1. */
+#define X86_FSW_C1 RT_BIT_32(9)
+/** Condition code 2. */
+#define X86_FSW_C2 RT_BIT_32(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)
+/** Condition code 3. */
+#define X86_FSW_C3 RT_BIT_32(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)
+/** @} */
+
+
+/** @name FPU control word flags.
+ * @{ */
+/** Exception Mask: Invalid operation. */
+#define X86_FCW_IM RT_BIT_32(0)
+/** Exception Mask: Denormalized operand. */
+#define X86_FCW_DM RT_BIT_32(1)
+/** Exception Mask: Zero divide. */
+#define X86_FCW_ZM RT_BIT_32(2)
+/** Exception Mask: Overflow. */
+#define X86_FCW_OM RT_BIT_32(3)
+/** Exception Mask: Underflow. */
+#define X86_FCW_UM RT_BIT_32(4)
+/** Exception Mask: Precision. */
+#define X86_FCW_PM RT_BIT_32(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: 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: 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)
+/** 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)
+
+/** 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)
+
+/** Rounding control mask. */
+#define X86_MXCSR_RC_MASK UINT16_C(0x6000)
+/** Rounding control: To nearest. */
+#define X86_MXCSR_RC_NEAREST UINT16_C(0x0000)
+/** Rounding control: Down. */
+#define X86_MXCSR_RC_DOWN UINT16_C(0x2000)
+/** Rounding control: Up. */
+#define X86_MXCSR_RC_UP UINT16_C(0x4000)
+/** Rounding control: Towards zero. */
+#define X86_MXCSR_RC_ZERO UINT16_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)
+/** @} */
+
+/**
+ * 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-Pointer Exception. */
+ X86_XCPT_XF = 0x13,
+ /** \#VE - Virtualization Exception. */
+ X86_XCPT_VE = 0x14,
+ /** \#SX - Security Exception. */
+ 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
+/** @} */
+
+/** @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
+
--- /dev/null
+/* $Id: the-linux-kernel.h $ */
+/** @file
+ * IPRT - Include all necessary headers for the Linux kernel.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___the_linux_kernel_h
+#define ___the_linux_kernel_h
+
+/*
+ * Include iprt/types.h to install the bool wrappers.
+ * Then use the linux bool type for all the stuff include here.
+ */
+#include <iprt/types.h>
+#define bool linux_bool
+
+#if RT_GNUC_PREREQ(4, 6)
+# pragma GCC diagnostic push
+#endif
+#if RT_GNUC_PREREQ(4, 2)
+# pragma GCC diagnostic ignored "-Wunused-parameter"
+# if !defined(__cplusplus) && RT_GNUC_PREREQ(4, 3)
+# pragma GCC diagnostic ignored "-Wold-style-declaration" /* 2.6.18-411.0.0.0.1.el5/build/include/asm/apic.h:110: warning: 'inline' is not at beginning of declaration [-Wold-style-declaration] */
+# endif
+#endif
+
+#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
+
+/* We only support 2.4 and 2.6 series kernels */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
+# error We only support 2.4 and 2.6 series kernels
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
+# error We only support 2.4 and 2.6 series kernels
+#endif
+
+#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
+# define MODVERSIONS
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 71)
+# include <linux/modversions.h>
+# endif
+#endif
+#ifndef KBUILD_STR
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16)
+# define KBUILD_STR(s) s
+# else
+# define KBUILD_STR(s) #s
+# endif
+#endif
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
+# include <linux/kconfig.h> /* for macro IS_ENABLED */
+# endif
+#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+# include <linux/semaphore.h>
+#else /* older kernels */
+# include <asm/semaphore.h>
+#endif /* older kernels */
+#include <linux/module.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+# include <linux/moduleparam.h>
+#endif
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+# include <linux/namei.h>
+#endif
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/sched.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+# include <linux/sched/rt.h>
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+# include <linux/sched/signal.h>
+# include <linux/sched/types.h>
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 7)
+# include <linux/jiffies.h>
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 16)
+# include <linux/ktime.h>
+# include <linux/hrtimer.h>
+#endif
+#include <linux/wait.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 71)
+# include <linux/cpu.h>
+# include <linux/notifier.h>
+#endif
+/* For the basic additions module */
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/compiler.h>
+#ifndef HAVE_UNLOCKED_IOCTL /* linux/fs.h defines this */
+# include <linux/smp_lock.h>
+#endif
+/* For the shared folders module */
+#include <linux/vmalloc.h>
+#define wchar_t linux_wchar_t
+#include <linux/nls.h>
+#undef wchar_t
+#include <asm/mman.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/div64.h>
+
+/* For thread-context hooks. */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) && defined(CONFIG_PREEMPT_NOTIFIERS)
+# include <linux/preempt.h>
+#endif
+
+/* for workqueue / task queues. */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 41)
+# include <linux/workqueue.h>
+#else
+# include <linux/tqueue.h>
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+# include <linux/kthread.h>
+#endif
+
+/* for cr4_init_shadow() / cpu_tlbstate. */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 20, 0)
+# include <asm/tlbflush.h>
+#endif
+
+/* for set_pages_x() */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
+# include <asm/set_memory.h>
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)
+# include <asm/smap.h>
+#else
+static inline void clac(void) { }
+static inline void stac(void) { }
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
+# ifndef page_to_pfn
+# define page_to_pfn(page) ((page) - mem_map)
+# endif
+#endif
+
+#ifndef DEFINE_WAIT
+# define DEFINE_WAIT(name) DECLARE_WAITQUEUE(name, current)
+#endif
+
+#ifndef __GFP_NOWARN
+# define __GFP_NOWARN 0
+#endif
+
+/*
+ * 2.4 / early 2.6 compatibility wrappers
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 7)
+
+# ifndef MAX_JIFFY_OFFSET
+# define MAX_JIFFY_OFFSET ((~0UL >> 1)-1)
+# endif
+
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 29) || LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+
+DECLINLINE(unsigned int) jiffies_to_msecs(unsigned long cJiffies)
+{
+# if HZ <= 1000 && !(1000 % HZ)
+ return (1000 / HZ) * cJiffies;
+# elif HZ > 1000 && !(HZ % 1000)
+ return (cJiffies + (HZ / 1000) - 1) / (HZ / 1000);
+# else
+ return (cJiffies * 1000) / HZ;
+# endif
+}
+
+DECLINLINE(unsigned long) msecs_to_jiffies(unsigned int cMillies)
+{
+# if HZ > 1000
+ if (cMillies > jiffies_to_msecs(MAX_JIFFY_OFFSET))
+ return MAX_JIFFY_OFFSET;
+# endif
+# if HZ <= 1000 && !(1000 % HZ)
+ return (cMillies + (1000 / HZ) - 1) / (1000 / HZ);
+# elif HZ > 1000 && !(HZ % 1000)
+ return cMillies * (HZ / 1000);
+# else
+ return (cMillies * HZ + 999) / 1000;
+# endif
+}
+
+# endif /* < 2.4.29 || >= 2.6.0 */
+
+#endif /* < 2.6.7 */
+
+/*
+ * 2.4 compatibility wrappers
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
+
+# define prepare_to_wait(q, wait, state) \
+ do { \
+ add_wait_queue(q, wait); \
+ set_current_state(state); \
+ } while (0)
+
+# define after_wait(wait) \
+ do { \
+ list_del_init(&(wait)->task_list); \
+ } while (0)
+
+# define finish_wait(q, wait) \
+ do { \
+ set_current_state(TASK_RUNNING); \
+ remove_wait_queue(q, wait); \
+ } while (0)
+
+#else /* >= 2.6.0 */
+
+# define after_wait(wait) do {} while (0)
+
+#endif /* >= 2.6.0 */
+
+/** @def TICK_NSEC
+ * The time between ticks in nsec */
+#ifndef TICK_NSEC
+# define TICK_NSEC (1000000000UL / HZ)
+#endif
+
+/*
+ * This sucks soooo badly on x86! Why don't they export __PAGE_KERNEL_EXEC so PAGE_KERNEL_EXEC would be usable?
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 8) && defined(RT_ARCH_AMD64)
+# define MY_PAGE_KERNEL_EXEC PAGE_KERNEL_EXEC
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 8) && defined(PAGE_KERNEL_EXEC) && defined(CONFIG_X86_PAE)
+# ifdef __PAGE_KERNEL_EXEC
+ /* >= 2.6.27 */
+# define MY_PAGE_KERNEL_EXEC __pgprot(boot_cpu_has(X86_FEATURE_PGE) ? __PAGE_KERNEL_EXEC | _PAGE_GLOBAL : __PAGE_KERNEL_EXEC)
+# else
+# define MY_PAGE_KERNEL_EXEC __pgprot(boot_cpu_has(X86_FEATURE_PGE) ? _PAGE_KERNEL_EXEC | _PAGE_GLOBAL : _PAGE_KERNEL_EXEC)
+# endif
+#else
+# define MY_PAGE_KERNEL_EXEC PAGE_KERNEL
+#endif
+
+
+/*
+ * The redhat hack section.
+ * - The current hacks are for 2.4.21-15.EL only.
+ */
+#ifndef NO_REDHAT_HACKS
+/* accounting. */
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
+# ifdef VM_ACCOUNT
+# define USE_RHEL4_MUNMAP
+# endif
+# endif
+
+/* backported remap_page_range. */
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
+# include <asm/tlb.h>
+# ifdef tlb_vma /* probably not good enough... */
+# define HAVE_26_STYLE_REMAP_PAGE_RANGE 1
+# endif
+# endif
+
+# ifndef RT_ARCH_AMD64
+/* In 2.6.9-22.ELsmp we have to call change_page_attr() twice when changing
+ * the page attributes from PAGE_KERNEL to something else, because there appears
+ * to be a bug in one of the many patches that redhat applied.
+ * It should be safe to do this on less buggy linux kernels too. ;-)
+ */
+# define MY_CHANGE_PAGE_ATTR(pPages, cPages, prot) \
+ do { \
+ if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) \
+ change_page_attr(pPages, cPages, prot); \
+ change_page_attr(pPages, cPages, prot); \
+ } while (0)
+# endif /* !RT_ARCH_AMD64 */
+#endif /* !NO_REDHAT_HACKS */
+
+#ifndef MY_CHANGE_PAGE_ATTR
+# ifdef RT_ARCH_AMD64 /** @todo This is a cheap hack, but it'll get around that 'else BUG();' in __change_page_attr(). */
+# define MY_CHANGE_PAGE_ATTR(pPages, cPages, prot) \
+ do { \
+ change_page_attr(pPages, cPages, PAGE_KERNEL_NOCACHE); \
+ change_page_attr(pPages, cPages, prot); \
+ } while (0)
+# else
+# define MY_CHANGE_PAGE_ATTR(pPages, cPages, prot) change_page_attr(pPages, cPages, prot)
+# endif
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
+# define MY_SET_PAGES_EXEC(pPages, cPages) set_pages_x(pPages, cPages)
+# define MY_SET_PAGES_NOEXEC(pPages, cPages) set_pages_nx(pPages, cPages)
+#else
+# define MY_SET_PAGES_EXEC(pPages, cPages) \
+ do { \
+ if (pgprot_val(MY_PAGE_KERNEL_EXEC) != pgprot_val(PAGE_KERNEL)) \
+ MY_CHANGE_PAGE_ATTR(pPages, cPages, MY_PAGE_KERNEL_EXEC); \
+ } while (0)
+# define MY_SET_PAGES_NOEXEC(pPages, cPages) \
+ do { \
+ if (pgprot_val(MY_PAGE_KERNEL_EXEC) != pgprot_val(PAGE_KERNEL)) \
+ MY_CHANGE_PAGE_ATTR(pPages, cPages, PAGE_KERNEL); \
+ } while (0)
+#endif
+
+/** @def ONE_MSEC_IN_JIFFIES
+ * The number of jiffies that make up 1 millisecond. Must be at least 1! */
+#if HZ <= 1000
+# define ONE_MSEC_IN_JIFFIES 1
+#elif !(HZ % 1000)
+# define ONE_MSEC_IN_JIFFIES (HZ / 1000)
+#else
+# define ONE_MSEC_IN_JIFFIES ((HZ + 999) / 1000)
+# error "HZ is not a multiple of 1000, the GIP stuff won't work right!"
+#endif
+
+/*
+ * Stop using the linux bool type.
+ */
+#undef bool
+
+#if RT_GNUC_PREREQ(4, 6)
+# pragma GCC diagnostic pop
+#endif
+
+/*
+ * There are post-2.6.24 kernels (confusingly with unchanged version number)
+ * which eliminate macros which were marked as deprecated.
+ */
+#ifndef __attribute_used__
+#define __attribute_used__ __used
+#endif
+
+/**
+ * Hack for shortening pointers on linux so we can stuff more stuff into the
+ * task_struct::comm field. This is used by the semaphore code but put here
+ * because we don't have any better place atm. Don't use outside IPRT, please.
+ */
+#ifdef RT_ARCH_AMD64
+# define IPRT_DEBUG_SEMS_ADDRESS(addr) ( ((long)(addr) & (long)~UINT64_C(0xfffffff000000000)) )
+#else
+# define IPRT_DEBUG_SEMS_ADDRESS(addr) ( (long)(addr) )
+#endif
+
+/**
+ * Puts semaphore info into the task_struct::comm field if IPRT_DEBUG_SEMS is
+ * defined.
+ */
+#ifdef IPRT_DEBUG_SEMS
+# define IPRT_DEBUG_SEMS_STATE(pThis, chState) \
+ snprintf(current->comm, sizeof(current->comm), "%c%lx", (chState), IPRT_DEBUG_SEMS_ADDRESS(pThis));
+#else
+# define IPRT_DEBUG_SEMS_STATE(pThis, chState) do { } while (0)
+#endif
+
+/**
+ * Puts semaphore info into the task_struct::comm field if IPRT_DEBUG_SEMS is
+ * defined.
+ */
+#ifdef IPRT_DEBUG_SEMS
+# define IPRT_DEBUG_SEMS_STATE_RC(pThis, chState, rc) \
+ snprintf(current->comm, sizeof(current->comm), "%c%lx:%d", (chState), IPRT_DEBUG_SEMS_ADDRESS(pThis), rc);
+#else
+# define IPRT_DEBUG_SEMS_STATE_RC(pThis, chState, rc) do { } while (0)
+#endif
+
+/** @name Macros for preserving EFLAGS.AC on 3.19+/amd64 paranoid.
+ * The AMD 64 switch_to in macro in arch/x86/include/asm/switch_to.h stopped
+ * restoring flags.
+ * @{ */
+#if defined(CONFIG_X86_SMAP) || defined(RT_STRICT) || defined(IPRT_WITH_EFLAGS_AC_PRESERVING)
+# include <iprt/asm-amd64-x86.h>
+# define IPRT_X86_EFL_AC RT_BIT(18)
+# define IPRT_LINUX_SAVE_EFL_AC() RTCCUINTREG fSavedEfl = ASMGetFlags()
+# define IPRT_LINUX_RESTORE_EFL_AC() ASMSetFlags(fSavedEfl)
+# define IPRT_LINUX_RESTORE_EFL_ONLY_AC() ASMChangeFlags(~IPRT_X86_EFL_AC, fSavedEfl & IPRT_X86_EFL_AC)
+#else
+# define IPRT_LINUX_SAVE_EFL_AC() do { } while (0)
+# define IPRT_LINUX_RESTORE_EFL_AC() do { } while (0)
+# define IPRT_LINUX_RESTORE_EFL_ONLY_AC() do { } while (0)
+#endif
+/** @} */
+
+/*
+ * There are some conflicting defines in iprt/param.h, sort them out here.
+ */
+#ifndef ___iprt_param_h
+# undef PAGE_SIZE
+# undef PAGE_OFFSET_MASK
+# include <iprt/param.h>
+#endif
+
+/*
+ * Some global indicator macros.
+ */
+/** @def IPRT_LINUX_HAS_HRTIMER
+ * Whether the kernel support high resolution timers (Linux kernel versions
+ * 2.6.28 and later (hrtimer_add_expires_ns() & schedule_hrtimeout). */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
+# define IPRT_LINUX_HAS_HRTIMER
+#endif
+
+/*
+ * Workqueue stuff, see initterm-r0drv-linux.c.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 41)
+typedef struct work_struct RTR0LNXWORKQUEUEITEM;
+#else
+typedef struct tq_struct RTR0LNXWORKQUEUEITEM;
+#endif
+DECLHIDDEN(void) rtR0LnxWorkqueuePush(RTR0LNXWORKQUEUEITEM *pWork, void (*pfnWorker)(RTR0LNXWORKQUEUEITEM *));
+DECLHIDDEN(void) rtR0LnxWorkqueueFlush(void);
+
+
+#endif
--- /dev/null
+/* $Id: alloc-r0drv.cpp $ */
+/** @file
+ * IPRT - Memory Allocation, Ring-0 Driver.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define RTMEM_NO_WRAP_TO_EF_APIS
+#include <iprt/mem.h>
+#include "internal/iprt.h"
+
+#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
+# include <iprt/asm-amd64-x86.h>
+#endif
+#include <iprt/assert.h>
+#ifdef RT_MORE_STRICT
+# include <iprt/mp.h>
+#endif
+#include <iprt/param.h>
+#include <iprt/string.h>
+#include <iprt/thread.h>
+#include "r0drv/alloc-r0drv.h"
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+#ifdef RT_STRICT
+# define RTR0MEM_STRICT
+#endif
+
+#ifdef RTR0MEM_STRICT
+# define RTR0MEM_FENCE_EXTRA 16
+#else
+# define RTR0MEM_FENCE_EXTRA 0
+#endif
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+#ifdef RTR0MEM_STRICT
+/** Fence data. */
+static uint8_t const g_abFence[RTR0MEM_FENCE_EXTRA] =
+{
+ 0x77, 0x88, 0x66, 0x99, 0x55, 0xaa, 0x44, 0xbb,
+ 0x33, 0xcc, 0x22, 0xdd, 0x11, 0xee, 0x00, 0xff
+};
+#endif
+
+
+/**
+ * Wrapper around rtR0MemAllocEx.
+ *
+ * @returns Pointer to the allocated memory block header.
+ * @param cb The number of bytes to allocate (sans header).
+ * @param fFlags The allocation flags.
+ */
+DECLINLINE(PRTMEMHDR) rtR0MemAlloc(size_t cb, uint32_t fFlags)
+{
+ PRTMEMHDR pHdr;
+ int rc = rtR0MemAllocEx(cb, fFlags, &pHdr);
+ if (RT_FAILURE(rc))
+ return NULL;
+ return pHdr;
+}
+
+
+RTDECL(void *) RTMemTmpAllocTag(size_t cb, const char *pszTag) RT_NO_THROW_DEF
+{
+ return RTMemAllocTag(cb, pszTag);
+}
+RT_EXPORT_SYMBOL(RTMemTmpAllocTag);
+
+
+RTDECL(void *) RTMemTmpAllocZTag(size_t cb, const char *pszTag) RT_NO_THROW_DEF
+{
+ return RTMemAllocZTag(cb, pszTag);
+}
+RT_EXPORT_SYMBOL(RTMemTmpAllocZTag);
+
+
+RTDECL(void) RTMemTmpFree(void *pv) RT_NO_THROW_DEF
+{
+ return RTMemFree(pv);
+}
+RT_EXPORT_SYMBOL(RTMemTmpFree);
+
+
+
+
+
+RTDECL(void *) RTMemAllocTag(size_t cb, const char *pszTag) RT_NO_THROW_DEF
+{
+ PRTMEMHDR pHdr;
+ RT_ASSERT_INTS_ON();
+ RT_NOREF_PV(pszTag);
+
+ pHdr = rtR0MemAlloc(cb + RTR0MEM_FENCE_EXTRA, 0);
+ if (pHdr)
+ {
+#ifdef RTR0MEM_STRICT
+ pHdr->cbReq = (uint32_t)cb; Assert(pHdr->cbReq == cb);
+ memcpy((uint8_t *)(pHdr + 1) + cb, &g_abFence[0], RTR0MEM_FENCE_EXTRA);
+#endif
+ return pHdr + 1;
+ }
+ return NULL;
+}
+RT_EXPORT_SYMBOL(RTMemAllocTag);
+
+
+RTDECL(void *) RTMemAllocZTag(size_t cb, const char *pszTag) RT_NO_THROW_DEF
+{
+ PRTMEMHDR pHdr;
+ RT_ASSERT_INTS_ON();
+ RT_NOREF_PV(pszTag);
+
+ pHdr = rtR0MemAlloc(cb + RTR0MEM_FENCE_EXTRA, RTMEMHDR_FLAG_ZEROED);
+ if (pHdr)
+ {
+#ifdef RTR0MEM_STRICT
+ pHdr->cbReq = (uint32_t)cb; Assert(pHdr->cbReq == cb);
+ memcpy((uint8_t *)(pHdr + 1) + cb, &g_abFence[0], RTR0MEM_FENCE_EXTRA);
+ return memset(pHdr + 1, 0, cb);
+#else
+ return memset(pHdr + 1, 0, pHdr->cb);
+#endif
+ }
+ return NULL;
+}
+RT_EXPORT_SYMBOL(RTMemAllocZTag);
+
+
+RTDECL(void *) RTMemAllocVarTag(size_t cbUnaligned, const char *pszTag)
+{
+ size_t cbAligned;
+ if (cbUnaligned >= 16)
+ cbAligned = RT_ALIGN_Z(cbUnaligned, 16);
+ else
+ cbAligned = RT_ALIGN_Z(cbUnaligned, sizeof(void *));
+ return RTMemAllocTag(cbAligned, pszTag);
+}
+RT_EXPORT_SYMBOL(RTMemAllocVarTag);
+
+
+RTDECL(void *) RTMemAllocZVarTag(size_t cbUnaligned, const char *pszTag)
+{
+ size_t cbAligned;
+ if (cbUnaligned >= 16)
+ cbAligned = RT_ALIGN_Z(cbUnaligned, 16);
+ else
+ cbAligned = RT_ALIGN_Z(cbUnaligned, sizeof(void *));
+ return RTMemAllocZTag(cbAligned, pszTag);
+}
+RT_EXPORT_SYMBOL(RTMemAllocZVarTag);
+
+
+RTDECL(void *) RTMemReallocTag(void *pvOld, size_t cbNew, const char *pszTag) RT_NO_THROW_DEF
+{
+ PRTMEMHDR pHdrOld;
+
+ /* Free. */
+ if (!cbNew && pvOld)
+ {
+ RTMemFree(pvOld);
+ return NULL;
+ }
+
+ /* Alloc. */
+ if (!pvOld)
+ return RTMemAllocTag(cbNew, pszTag);
+
+ /*
+ * Realloc.
+ */
+ pHdrOld = (PRTMEMHDR)pvOld - 1;
+ RT_ASSERT_PREEMPTIBLE();
+
+ if (pHdrOld->u32Magic == RTMEMHDR_MAGIC)
+ {
+ PRTMEMHDR pHdrNew;
+
+ /* If there is sufficient space in the old block and we don't cause
+ substantial internal fragmentation, reuse the old block. */
+ if ( pHdrOld->cb >= cbNew + RTR0MEM_FENCE_EXTRA
+ && pHdrOld->cb - (cbNew + RTR0MEM_FENCE_EXTRA) <= 128)
+ {
+ pHdrOld->cbReq = (uint32_t)cbNew; Assert(pHdrOld->cbReq == cbNew);
+#ifdef RTR0MEM_STRICT
+ memcpy((uint8_t *)(pHdrOld + 1) + cbNew, &g_abFence[0], RTR0MEM_FENCE_EXTRA);
+#endif
+ return pvOld;
+ }
+
+ /* Allocate a new block and copy over the content. */
+ pHdrNew = rtR0MemAlloc(cbNew + RTR0MEM_FENCE_EXTRA, 0);
+ if (pHdrNew)
+ {
+ size_t cbCopy = RT_MIN(pHdrOld->cb, pHdrNew->cb);
+ memcpy(pHdrNew + 1, pvOld, cbCopy);
+#ifdef RTR0MEM_STRICT
+ pHdrNew->cbReq = (uint32_t)cbNew; Assert(pHdrNew->cbReq == cbNew);
+ memcpy((uint8_t *)(pHdrNew + 1) + cbNew, &g_abFence[0], RTR0MEM_FENCE_EXTRA);
+ AssertReleaseMsg(!memcmp((uint8_t *)(pHdrOld + 1) + pHdrOld->cbReq, &g_abFence[0], RTR0MEM_FENCE_EXTRA),
+ ("pHdr=%p pvOld=%p cbReq=%u cb=%u cbNew=%zu fFlags=%#x\n"
+ "fence: %.*Rhxs\n"
+ "expected: %.*Rhxs\n",
+ pHdrOld, pvOld, pHdrOld->cbReq, pHdrOld->cb, cbNew, pHdrOld->fFlags,
+ RTR0MEM_FENCE_EXTRA, (uint8_t *)(pHdrOld + 1) + pHdrOld->cbReq,
+ RTR0MEM_FENCE_EXTRA, &g_abFence[0]));
+#endif
+ rtR0MemFree(pHdrOld);
+ return pHdrNew + 1;
+ }
+ }
+ else
+ AssertMsgFailed(("pHdrOld->u32Magic=%RX32 pvOld=%p cbNew=%#zx\n", pHdrOld->u32Magic, pvOld, cbNew));
+
+ return NULL;
+}
+RT_EXPORT_SYMBOL(RTMemReallocTag);
+
+
+RTDECL(void) RTMemFree(void *pv) RT_NO_THROW_DEF
+{
+ PRTMEMHDR pHdr;
+ RT_ASSERT_INTS_ON();
+
+ if (!pv)
+ return;
+ pHdr = (PRTMEMHDR)pv - 1;
+ if (pHdr->u32Magic == RTMEMHDR_MAGIC)
+ {
+ Assert(!(pHdr->fFlags & RTMEMHDR_FLAG_ALLOC_EX));
+ Assert(!(pHdr->fFlags & RTMEMHDR_FLAG_EXEC));
+#ifdef RTR0MEM_STRICT
+ AssertReleaseMsg(!memcmp((uint8_t *)(pHdr + 1) + pHdr->cbReq, &g_abFence[0], RTR0MEM_FENCE_EXTRA),
+ ("pHdr=%p pv=%p cbReq=%u cb=%u fFlags=%#x\n"
+ "fence: %.*Rhxs\n"
+ "expected: %.*Rhxs\n",
+ pHdr, pv, pHdr->cbReq, pHdr->cb, pHdr->fFlags,
+ RTR0MEM_FENCE_EXTRA, (uint8_t *)(pHdr + 1) + pHdr->cbReq,
+ RTR0MEM_FENCE_EXTRA, &g_abFence[0]));
+#endif
+ rtR0MemFree(pHdr);
+ }
+ else
+ AssertMsgFailed(("pHdr->u32Magic=%RX32 pv=%p\n", pHdr->u32Magic, pv));
+}
+RT_EXPORT_SYMBOL(RTMemFree);
+
+
+
+
+
+
+RTDECL(void *) RTMemExecAllocTag(size_t cb, const char *pszTag) RT_NO_THROW_DEF
+{
+ PRTMEMHDR pHdr;
+#ifdef RT_OS_SOLARIS /** @todo figure out why */
+ RT_ASSERT_INTS_ON();
+#else
+ RT_ASSERT_PREEMPTIBLE();
+#endif
+ RT_NOREF_PV(pszTag);
+
+
+ pHdr = rtR0MemAlloc(cb + RTR0MEM_FENCE_EXTRA, RTMEMHDR_FLAG_EXEC);
+ if (pHdr)
+ {
+#ifdef RTR0MEM_STRICT
+ pHdr->cbReq = (uint32_t)cb; Assert(pHdr->cbReq == cb);
+ memcpy((uint8_t *)(pHdr + 1) + cb, &g_abFence[0], RTR0MEM_FENCE_EXTRA);
+#endif
+ return pHdr + 1;
+ }
+ return NULL;
+}
+RT_EXPORT_SYMBOL(RTMemExecAllocTag);
+
+
+RTDECL(void) RTMemExecFree(void *pv, size_t cb) RT_NO_THROW_DEF
+{
+ PRTMEMHDR pHdr;
+ RT_ASSERT_INTS_ON();
+ RT_NOREF_PV(cb);
+
+ if (!pv)
+ return;
+ pHdr = (PRTMEMHDR)pv - 1;
+ if (pHdr->u32Magic == RTMEMHDR_MAGIC)
+ {
+ Assert(!(pHdr->fFlags & RTMEMHDR_FLAG_ALLOC_EX));
+#ifdef RTR0MEM_STRICT
+ AssertReleaseMsg(!memcmp((uint8_t *)(pHdr + 1) + pHdr->cbReq, &g_abFence[0], RTR0MEM_FENCE_EXTRA),
+ ("pHdr=%p pv=%p cbReq=%u cb=%u fFlags=%#x\n"
+ "fence: %.*Rhxs\n"
+ "expected: %.*Rhxs\n",
+ pHdr, pv, pHdr->cbReq, pHdr->cb, pHdr->fFlags,
+ RTR0MEM_FENCE_EXTRA, (uint8_t *)(pHdr + 1) + pHdr->cbReq,
+ RTR0MEM_FENCE_EXTRA, &g_abFence[0]));
+#endif
+ rtR0MemFree(pHdr);
+ }
+ else
+ AssertMsgFailed(("pHdr->u32Magic=%RX32 pv=%p\n", pHdr->u32Magic, pv));
+}
+RT_EXPORT_SYMBOL(RTMemExecFree);
+
+
+
+
+RTDECL(int) RTMemAllocExTag(size_t cb, size_t cbAlignment, uint32_t fFlags, const char *pszTag, void **ppv) RT_NO_THROW_DEF
+{
+ uint32_t fHdrFlags = RTMEMHDR_FLAG_ALLOC_EX;
+ PRTMEMHDR pHdr;
+ int rc;
+ RT_NOREF_PV(pszTag);
+
+ RT_ASSERT_PREEMPT_CPUID_VAR();
+ if (!(fFlags & RTMEMALLOCEX_FLAGS_ANY_CTX_ALLOC))
+ RT_ASSERT_INTS_ON();
+
+ /*
+ * Fake up some alignment support.
+ */
+ AssertMsgReturn(cbAlignment <= sizeof(void *), ("%zu (%#x)\n", cbAlignment, cbAlignment), VERR_UNSUPPORTED_ALIGNMENT);
+ if (cb < cbAlignment)
+ cb = cbAlignment;
+
+ /*
+ * Validate and convert flags.
+ */
+ AssertMsgReturn(!(fFlags & ~RTMEMALLOCEX_FLAGS_VALID_MASK_R0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
+ if (fFlags & RTMEMALLOCEX_FLAGS_ZEROED)
+ fHdrFlags |= RTMEMHDR_FLAG_ZEROED;
+ if (fFlags & RTMEMALLOCEX_FLAGS_EXEC)
+ fHdrFlags |= RTMEMHDR_FLAG_EXEC;
+ if (fFlags & RTMEMALLOCEX_FLAGS_ANY_CTX_ALLOC)
+ fHdrFlags |= RTMEMHDR_FLAG_ANY_CTX_ALLOC;
+ if (fFlags & RTMEMALLOCEX_FLAGS_ANY_CTX_FREE)
+ fHdrFlags |= RTMEMHDR_FLAG_ANY_CTX_FREE;
+
+ /*
+ * Do the allocation.
+ */
+ rc = rtR0MemAllocEx(cb + RTR0MEM_FENCE_EXTRA, fHdrFlags, &pHdr);
+ if (RT_SUCCESS(rc))
+ {
+ void *pv;
+
+ Assert(pHdr->cbReq == cb + RTR0MEM_FENCE_EXTRA);
+ Assert((pHdr->fFlags & fFlags) == fFlags);
+
+ /*
+ * Calc user pointer, initialize the memory if requested, and if
+ * memory strictness is enable set up the fence.
+ */
+ pv = pHdr + 1;
+ *ppv = pv;
+ if (fFlags & RTMEMHDR_FLAG_ZEROED)
+ memset(pv, 0, pHdr->cb);
+
+#ifdef RTR0MEM_STRICT
+ pHdr->cbReq = (uint32_t)cb;
+ memcpy((uint8_t *)pv + cb, &g_abFence[0], RTR0MEM_FENCE_EXTRA);
+#endif
+ }
+ else if (rc == VERR_NO_MEMORY && (fFlags & RTMEMALLOCEX_FLAGS_EXEC))
+ rc = VERR_NO_EXEC_MEMORY;
+
+ RT_ASSERT_PREEMPT_CPUID();
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTMemAllocExTag);
+
+
+RTDECL(void) RTMemFreeEx(void *pv, size_t cb) RT_NO_THROW_DEF
+{
+ PRTMEMHDR pHdr;
+ RT_NOREF_PV(cb);
+
+ if (!pv)
+ return;
+
+ AssertPtr(pv);
+ pHdr = (PRTMEMHDR)pv - 1;
+ if (pHdr->u32Magic == RTMEMHDR_MAGIC)
+ {
+ RT_ASSERT_PREEMPT_CPUID_VAR();
+
+ Assert(pHdr->fFlags & RTMEMHDR_FLAG_ALLOC_EX);
+ if (!(pHdr->fFlags & RTMEMHDR_FLAG_ANY_CTX_FREE))
+ RT_ASSERT_INTS_ON();
+ AssertMsg(pHdr->cbReq == cb, ("cbReq=%zu cb=%zu\n", pHdr->cb, cb));
+
+#ifdef RTR0MEM_STRICT
+ AssertReleaseMsg(!memcmp((uint8_t *)(pHdr + 1) + pHdr->cbReq, &g_abFence[0], RTR0MEM_FENCE_EXTRA),
+ ("pHdr=%p pv=%p cbReq=%u cb=%u fFlags=%#x\n"
+ "fence: %.*Rhxs\n"
+ "expected: %.*Rhxs\n",
+ pHdr, pv, pHdr->cbReq, pHdr->cb, pHdr->fFlags,
+ RTR0MEM_FENCE_EXTRA, (uint8_t *)(pHdr + 1) + pHdr->cbReq,
+ RTR0MEM_FENCE_EXTRA, &g_abFence[0]));
+#endif
+ rtR0MemFree(pHdr);
+ RT_ASSERT_PREEMPT_CPUID();
+ }
+ else
+ AssertMsgFailed(("pHdr->u32Magic=%RX32 pv=%p\n", pHdr->u32Magic, pv));
+}
+RT_EXPORT_SYMBOL(RTMemFreeEx);
+
--- /dev/null
+/* $Id: alloc-r0drv.h $ */
+/** @file
+ * IPRT - Memory Allocation, Ring-0 Driver.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___r0drv_alloc_r0drv_h
+#define ___r0drv_alloc_r0drv_h
+
+#include <iprt/cdefs.h>
+#include <iprt/types.h>
+#include <iprt/mem.h>
+#include "internal/magics.h"
+
+RT_C_DECLS_BEGIN
+
+/**
+ * Header which heading all memory blocks.
+ */
+typedef struct RTMEMHDR
+{
+ /** Magic (RTMEMHDR_MAGIC). */
+ uint32_t u32Magic;
+ /** Block flags (RTMEMHDR_FLAG_*). */
+ uint32_t fFlags;
+ /** The actual size of the block, header not included. */
+ uint32_t cb;
+ /** The requested allocation size. */
+ uint32_t cbReq;
+} RTMEMHDR, *PRTMEMHDR;
+
+
+/** @name RTMEMHDR::fFlags.
+ * @{ */
+/** Clear the allocated memory. */
+#define RTMEMHDR_FLAG_ZEROED RT_BIT(0)
+/** Executable flag. */
+#define RTMEMHDR_FLAG_EXEC RT_BIT(1)
+/** Use allocation method suitable for any context. */
+#define RTMEMHDR_FLAG_ANY_CTX_ALLOC RT_BIT(2)
+/** Use allocation method which allow for freeing in any context. */
+#define RTMEMHDR_FLAG_ANY_CTX_FREE RT_BIT(3)
+/** Both alloc and free in any context (or we're just darn lazy). */
+#define RTMEMHDR_FLAG_ANY_CTX (RTMEMHDR_FLAG_ANY_CTX_ALLOC | RTMEMHDR_FLAG_ANY_CTX_FREE)
+/** Indicate that it was allocated by rtR0MemAllocExTag. */
+#define RTMEMHDR_FLAG_ALLOC_EX RT_BIT(4)
+#ifdef RT_OS_LINUX
+/** Linux: Allocated using vm_area hacks. */
+# define RTMEMHDR_FLAG_EXEC_VM_AREA RT_BIT(29)
+/** Linux: Allocated from the special heap for executable memory. */
+# define RTMEMHDR_FLAG_EXEC_HEAP RT_BIT(30)
+/** Linux: Allocated by kmalloc() instead of vmalloc(). */
+# define RTMEMHDR_FLAG_KMALLOC RT_BIT(31)
+#endif
+/** @} */
+
+
+/**
+ * Heap allocation back end for ring-0.
+ *
+ * @returns IPRT status code. VERR_NO_MEMORY suffices for RTMEMHDR_FLAG_EXEC,
+ * the caller will change it to VERR_NO_EXEC_MEMORY when appropriate.
+ *
+ * @param cb The amount of memory requested by the user. This does
+ * not include the header.
+ * @param fFlags The allocation flags and more. These should be
+ * assigned to RTMEMHDR::fFlags together with any flags
+ * the backend might be using.
+ * @param ppHdr Where to return the memory header on success.
+ */
+DECLHIDDEN(int) rtR0MemAllocEx(size_t cb, uint32_t fFlags, PRTMEMHDR *ppHdr);
+
+/**
+ * Free memory allocated by rtR0MemAllocEx.
+ * @param pHdr The memory block to free. (Never NULL.)
+ */
+DECLHIDDEN(void) rtR0MemFree(PRTMEMHDR pHdr);
+
+RT_C_DECLS_END
+#endif
+
--- /dev/null
+/* $Id: semspinmutex-r0drv-generic.c $ */
+/** @file
+ * IPRT - Spinning Mutex Semaphores, Ring-0 Driver, Generic.
+ */
+
+/*
+ * Copyright (C) 2009-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#ifdef RT_OS_WINDOWS
+# include "../nt/the-nt-kernel.h"
+#endif
+#include "internal/iprt.h"
+
+#include <iprt/semaphore.h>
+#include <iprt/asm.h>
+#include <iprt/asm-amd64-x86.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/mem.h>
+#include <iprt/thread.h>
+#include "internal/magics.h"
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * Saved state information.
+ */
+typedef struct RTSEMSPINMUTEXSTATE
+{
+ /** Saved flags register. */
+ RTCCUINTREG fSavedFlags;
+ /** Preemption state. */
+ RTTHREADPREEMPTSTATE PreemptState;
+ /** Whether to spin or sleep. */
+ bool fSpin;
+ /** Whether the flags have been saved. */
+ bool fValidFlags;
+} RTSEMSPINMUTEXSTATE;
+
+/**
+ * Spinning mutex semaphore.
+ */
+typedef struct RTSEMSPINMUTEXINTERNAL
+{
+ /** Magic value (RTSEMSPINMUTEX_MAGIC)
+ * RTCRITSECT_MAGIC is the value of an initialized & operational section. */
+ uint32_t volatile u32Magic;
+ /** Flags. This is a combination of RTSEMSPINMUTEX_FLAGS_XXX and
+ * RTSEMSPINMUTEX_INT_FLAGS_XXX. */
+ uint32_t volatile fFlags;
+ /** The owner thread.
+ * This is NIL if the semaphore is not owned by anyone. */
+ RTNATIVETHREAD volatile hOwner;
+ /** Number of threads that are fighting for the lock. */
+ int32_t volatile cLockers;
+ /** The semaphore to block on. */
+ RTSEMEVENT hEventSem;
+ /** Saved state information of the owner.
+ * This will be restored by RTSemSpinRelease. */
+ RTSEMSPINMUTEXSTATE SavedState;
+} RTSEMSPINMUTEXINTERNAL;
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/*#define RTSEMSPINMUTEX_INT_FLAGS_MUST*/
+
+/** Validates the handle, returning if invalid. */
+#define RTSEMSPINMUTEX_VALIDATE_RETURN(pThis) \
+ do \
+ { \
+ uint32_t u32Magic; \
+ AssertPtr(pThis); \
+ u32Magic = (pThis)->u32Magic; \
+ if (u32Magic != RTSEMSPINMUTEX_MAGIC) \
+ { \
+ AssertMsgFailed(("u32Magic=%#x pThis=%p\n", u32Magic, pThis)); \
+ return u32Magic == RTSEMSPINMUTEX_MAGIC_DEAD ? VERR_SEM_DESTROYED : VERR_INVALID_HANDLE; \
+ } \
+ } while (0)
+
+
+RTDECL(int) RTSemSpinMutexCreate(PRTSEMSPINMUTEX phSpinMtx, uint32_t fFlags)
+{
+ RTSEMSPINMUTEXINTERNAL *pThis;
+ int rc;
+
+ AssertReturn(!(fFlags & ~RTSEMSPINMUTEX_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
+ AssertPtr(phSpinMtx);
+
+ /*
+ * Allocate and initialize the structure.
+ */
+ pThis = (RTSEMSPINMUTEXINTERNAL *)RTMemAllocZ(sizeof(*pThis));
+ if (!pThis)
+ return VERR_NO_MEMORY;
+ pThis->u32Magic = RTSEMSPINMUTEX_MAGIC;
+ pThis->fFlags = fFlags;
+ pThis->hOwner = NIL_RTNATIVETHREAD;
+ pThis->cLockers = 0;
+ rc = RTSemEventCreateEx(&pThis->hEventSem, RTSEMEVENT_FLAGS_NO_LOCK_VAL, NIL_RTLOCKVALCLASS, NULL);
+ if (RT_SUCCESS(rc))
+ {
+ *phSpinMtx = pThis;
+ return VINF_SUCCESS;
+ }
+
+ RTMemFree(pThis);
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTSemSpinMutexCreate);
+
+
+/**
+ * Helper for RTSemSpinMutexTryRequest and RTSemSpinMutexRequest.
+ *
+ * This will check the current context and see if it's usui
+ *
+ * @returns VINF_SUCCESS or VERR_SEM_BAD_CONTEXT.
+ * @param pState Output structure.
+ */
+static int rtSemSpinMutexEnter(RTSEMSPINMUTEXSTATE *pState, RTSEMSPINMUTEXINTERNAL *pThis)
+{
+#ifndef RT_OS_WINDOWS
+ RTTHREADPREEMPTSTATE const StateInit = RTTHREADPREEMPTSTATE_INITIALIZER;
+#endif
+ int rc = VINF_SUCCESS;
+
+ /** @todo Later #1: When entering in interrupt context and we're not able to
+ * wake up threads from it, we could try switch the lock into pure
+ * spinlock mode. This would require that there are no other threads
+ * currently waiting on it and that the RTSEMSPINMUTEX_FLAGS_IRQ_SAFE
+ * flag is set.
+ *
+ * Later #2: Similarly, it is possible to turn on the
+ * RTSEMSPINMUTEX_FLAGS_IRQ_SAFE at run time if we manage to grab the
+ * semaphore ownership at interrupt time. We might want to try delay the
+ * RTSEMSPINMUTEX_FLAGS_IRQ_SAFE even, since we're fine if we get it...
+ */
+
+#ifdef RT_OS_WINDOWS
+ /*
+ * NT: IRQL <= DISPATCH_LEVEL for waking up threads; IRQL < DISPATCH_LEVEL for sleeping.
+ */
+ pState->PreemptState.uchOldIrql = KeGetCurrentIrql();
+ if (pState->PreemptState.uchOldIrql > DISPATCH_LEVEL)
+ return VERR_SEM_BAD_CONTEXT;
+
+ if (pState->PreemptState.uchOldIrql >= DISPATCH_LEVEL)
+ pState->fSpin = true;
+ else
+ {
+ pState->fSpin = false;
+ KeRaiseIrql(DISPATCH_LEVEL, &pState->PreemptState.uchOldIrql);
+ Assert(pState->PreemptState.uchOldIrql < DISPATCH_LEVEL);
+ }
+
+#elif defined(RT_OS_SOLARIS)
+ /*
+ * Solaris: RTSemEventSignal will do bad stuff on S10 if interrupts are disabled.
+ */
+ if (!ASMIntAreEnabled())
+ return VERR_SEM_BAD_CONTEXT;
+
+ pState->fSpin = !RTThreadPreemptIsEnabled(NIL_RTTHREAD);
+ if (RTThreadIsInInterrupt(NIL_RTTHREAD))
+ {
+ if (!(pThis->fFlags & RTSEMSPINMUTEX_FLAGS_IRQ_SAFE))
+ rc = VINF_SEM_BAD_CONTEXT; /* Try, but owner might be interrupted. */
+ pState->fSpin = true;
+ }
+ pState->PreemptState = StateInit;
+ RTThreadPreemptDisable(&pState->PreemptState);
+
+#elif defined(RT_OS_LINUX) || defined(RT_OS_OS2)
+ /*
+ * OSes on which RTSemEventSignal can be called from any context.
+ */
+ pState->fSpin = !RTThreadPreemptIsEnabled(NIL_RTTHREAD);
+ if (RTThreadIsInInterrupt(NIL_RTTHREAD))
+ {
+ if (!(pThis->fFlags & RTSEMSPINMUTEX_FLAGS_IRQ_SAFE))
+ rc = VINF_SEM_BAD_CONTEXT; /* Try, but owner might be interrupted. */
+ pState->fSpin = true;
+ }
+ pState->PreemptState = StateInit;
+ RTThreadPreemptDisable(&pState->PreemptState);
+
+#else /* PORTME: Check for context where we cannot wake up threads. */
+ /*
+ * Default: ASSUME thread can be woken up if interrupts are enabled and
+ * we're not in an interrupt context.
+ * ASSUME that we can go to sleep if preemption is enabled.
+ */
+ if ( RTThreadIsInInterrupt(NIL_RTTHREAD)
+ || !ASMIntAreEnabled())
+ return VERR_SEM_BAD_CONTEXT;
+
+ pState->fSpin = !RTThreadPreemptIsEnabled(NIL_RTTHREAD);
+ pState->PreemptState = StateInit;
+ RTThreadPreemptDisable(&pState->PreemptState);
+#endif
+
+ /*
+ * Disable interrupts if necessary.
+ */
+ pState->fValidFlags = !!(pThis->fFlags & RTSEMSPINMUTEX_FLAGS_IRQ_SAFE);
+ if (pState->fValidFlags)
+ pState->fSavedFlags = ASMIntDisableFlags();
+ else
+ pState->fSavedFlags = 0;
+
+ return rc;
+}
+
+
+/**
+ * Helper for RTSemSpinMutexTryRequest, RTSemSpinMutexRequest and
+ * RTSemSpinMutexRelease.
+ *
+ * @param pState
+ */
+DECL_FORCE_INLINE(void) rtSemSpinMutexLeave(RTSEMSPINMUTEXSTATE *pState)
+{
+ /*
+ * Restore the interrupt flag.
+ */
+ if (pState->fValidFlags)
+ ASMSetFlags(pState->fSavedFlags);
+
+#ifdef RT_OS_WINDOWS
+ /*
+ * NT: Lower the IRQL if we raised it.
+ */
+ if (pState->PreemptState.uchOldIrql < DISPATCH_LEVEL)
+ KeLowerIrql(pState->PreemptState.uchOldIrql);
+#else
+ /*
+ * Default: Restore preemption.
+ */
+ RTThreadPreemptRestore(&pState->PreemptState);
+#endif
+}
+
+
+RTDECL(int) RTSemSpinMutexTryRequest(RTSEMSPINMUTEX hSpinMtx)
+{
+ RTSEMSPINMUTEXINTERNAL *pThis = hSpinMtx;
+ RTNATIVETHREAD hSelf = RTThreadNativeSelf();
+ RTSEMSPINMUTEXSTATE State;
+ bool fRc;
+ int rc;
+
+ Assert(hSelf != NIL_RTNATIVETHREAD);
+ RTSEMSPINMUTEX_VALIDATE_RETURN(pThis);
+
+ /*
+ * Check context, disable preemption and save flags if necessary.
+ */
+ rc = rtSemSpinMutexEnter(&State, pThis);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /*
+ * Try take the ownership.
+ */
+ ASMAtomicCmpXchgHandle(&pThis->hOwner, hSelf, NIL_RTNATIVETHREAD, fRc);
+ if (!fRc)
+ {
+ /* Busy, too bad. Check for attempts at nested access. */
+ rc = VERR_SEM_BUSY;
+ if (RT_UNLIKELY(pThis->hOwner == hSelf))
+ {
+ AssertMsgFailed(("%p attempt at nested access\n"));
+ rc = VERR_SEM_NESTED;
+ }
+
+ rtSemSpinMutexLeave(&State);
+ return rc;
+ }
+
+ /*
+ * We're the semaphore owner.
+ */
+ ASMAtomicIncS32(&pThis->cLockers);
+ pThis->SavedState = State;
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTSemSpinMutexTryRequest);
+
+
+RTDECL(int) RTSemSpinMutexRequest(RTSEMSPINMUTEX hSpinMtx)
+{
+ RTSEMSPINMUTEXINTERNAL *pThis = hSpinMtx;
+ RTNATIVETHREAD hSelf = RTThreadNativeSelf();
+ RTSEMSPINMUTEXSTATE State;
+ bool fRc;
+ int rc;
+
+ Assert(hSelf != NIL_RTNATIVETHREAD);
+ RTSEMSPINMUTEX_VALIDATE_RETURN(pThis);
+
+ /*
+ * Check context, disable preemption and save flags if necessary.
+ */
+ rc = rtSemSpinMutexEnter(&State, pThis);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /*
+ * Try take the ownership.
+ */
+ ASMAtomicIncS32(&pThis->cLockers);
+ ASMAtomicCmpXchgHandle(&pThis->hOwner, hSelf, NIL_RTNATIVETHREAD, fRc);
+ if (!fRc)
+ {
+ uint32_t cSpins;
+
+ /*
+ * It's busy. Check if it's an attempt at nested access.
+ */
+ if (RT_UNLIKELY(pThis->hOwner == hSelf))
+ {
+ AssertMsgFailed(("%p attempt at nested access\n"));
+ rtSemSpinMutexLeave(&State);
+ return VERR_SEM_NESTED;
+ }
+
+ /*
+ * Return if we're in interrupt context and the semaphore isn't
+ * configure to be interrupt safe.
+ */
+ if (rc == VINF_SEM_BAD_CONTEXT)
+ {
+ rtSemSpinMutexLeave(&State);
+ return VERR_SEM_BAD_CONTEXT;
+ }
+
+ /*
+ * Ok, we have to wait.
+ */
+ if (State.fSpin)
+ {
+ for (cSpins = 0; ; cSpins++)
+ {
+ ASMAtomicCmpXchgHandle(&pThis->hOwner, hSelf, NIL_RTNATIVETHREAD, fRc);
+ if (fRc)
+ break;
+ ASMNopPause();
+ if (RT_UNLIKELY(pThis->u32Magic != RTSEMSPINMUTEX_MAGIC))
+ {
+ rtSemSpinMutexLeave(&State);
+ return VERR_SEM_DESTROYED;
+ }
+
+ /*
+ * "Yield" once in a while. This may lower our IRQL/PIL which
+ * may preempting us, and it will certainly stop the hammering
+ * of hOwner for a little while.
+ */
+ if ((cSpins & 0x7f) == 0x1f)
+ {
+ rtSemSpinMutexLeave(&State);
+ rtSemSpinMutexEnter(&State, pThis);
+ Assert(State.fSpin);
+ }
+ }
+ }
+ else
+ {
+ for (cSpins = 0;; cSpins++)
+ {
+ ASMAtomicCmpXchgHandle(&pThis->hOwner, hSelf, NIL_RTNATIVETHREAD, fRc);
+ if (fRc)
+ break;
+ ASMNopPause();
+ if (RT_UNLIKELY(pThis->u32Magic != RTSEMSPINMUTEX_MAGIC))
+ {
+ rtSemSpinMutexLeave(&State);
+ return VERR_SEM_DESTROYED;
+ }
+
+ if ((cSpins & 15) == 15) /* spin a bit before going sleep (again). */
+ {
+ rtSemSpinMutexLeave(&State);
+
+ rc = RTSemEventWait(pThis->hEventSem, RT_INDEFINITE_WAIT);
+ ASMCompilerBarrier();
+ if (RT_SUCCESS(rc))
+ AssertReturn(pThis->u32Magic == RTSEMSPINMUTEX_MAGIC, VERR_SEM_DESTROYED);
+ else if (rc == VERR_INTERRUPTED)
+ AssertRC(rc); /* shouldn't happen */
+ else
+ {
+ AssertRC(rc);
+ return rc;
+ }
+
+ rc = rtSemSpinMutexEnter(&State, pThis);
+ AssertRCReturn(rc, rc);
+ Assert(!State.fSpin);
+ }
+ }
+ }
+ }
+
+ /*
+ * We're the semaphore owner.
+ */
+ pThis->SavedState = State;
+ Assert(pThis->hOwner == hSelf);
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTSemSpinMutexRequest);
+
+
+RTDECL(int) RTSemSpinMutexRelease(RTSEMSPINMUTEX hSpinMtx)
+{
+ RTSEMSPINMUTEXINTERNAL *pThis = hSpinMtx;
+ RTNATIVETHREAD hSelf = RTThreadNativeSelf();
+ uint32_t cLockers;
+ RTSEMSPINMUTEXSTATE State;
+ bool fRc;
+
+ Assert(hSelf != NIL_RTNATIVETHREAD);
+ RTSEMSPINMUTEX_VALIDATE_RETURN(pThis);
+
+ /*
+ * Get the saved state and try release the semaphore.
+ */
+ State = pThis->SavedState;
+ ASMCompilerBarrier();
+ ASMAtomicCmpXchgHandle(&pThis->hOwner, NIL_RTNATIVETHREAD, hSelf, fRc);
+ AssertMsgReturn(fRc,
+ ("hOwner=%p hSelf=%p cLockers=%d\n", pThis->hOwner, hSelf, pThis->cLockers),
+ VERR_NOT_OWNER);
+
+ cLockers = ASMAtomicDecS32(&pThis->cLockers);
+ rtSemSpinMutexLeave(&State);
+ if (cLockers > 0)
+ {
+ int rc = RTSemEventSignal(pThis->hEventSem);
+ AssertReleaseMsg(RT_SUCCESS(rc), ("RTSemEventSignal -> %Rrc\n", rc));
+ }
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTSemSpinMutexRelease);
+
+
+RTDECL(int) RTSemSpinMutexDestroy(RTSEMSPINMUTEX hSpinMtx)
+{
+ RTSEMSPINMUTEXINTERNAL *pThis;
+ RTSEMEVENT hEventSem;
+ int rc;
+
+ if (hSpinMtx == NIL_RTSEMSPINMUTEX)
+ return VINF_SUCCESS;
+ pThis = hSpinMtx;
+ RTSEMSPINMUTEX_VALIDATE_RETURN(pThis);
+
+ /* No destruction races allowed! */
+ AssertMsg( pThis->cLockers == 0
+ && pThis->hOwner == NIL_RTNATIVETHREAD,
+ ("pThis=%p cLockers=%d hOwner=%p\n", pThis, pThis->cLockers, pThis->hOwner));
+
+ /*
+ * Invalidate the structure, free the mutex and free the structure.
+ */
+ ASMAtomicWriteU32(&pThis->u32Magic, RTSEMSPINMUTEX_MAGIC_DEAD);
+ hEventSem = pThis->hEventSem;
+ pThis->hEventSem = NIL_RTSEMEVENT;
+ rc = RTSemEventDestroy(hEventSem); AssertRC(rc);
+
+ RTMemFree(pThis);
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTSemSpinMutexDestroy);
+
--- /dev/null
+/* $Id: initterm-r0drv.cpp $ */
+/** @file
+ * IPRT - Initialization & Termination, R0 Driver, Common.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/initterm.h>
+#include "internal/iprt.h"
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/mp.h>
+#include <iprt/thread.h>
+#ifndef IN_GUEST /* play safe for now */
+# include "r0drv/mp-r0drv.h"
+# include "r0drv/power-r0drv.h"
+#endif
+
+#include "internal/initterm.h"
+#include "internal/mem.h"
+#include "internal/thread.h"
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/** Count of current IPRT users.
+ * In ring-0 several drivers / kmods / kexts / wossnames may share the
+ * same runtime code. So, we need to keep count in order not to terminate
+ * it prematurely. */
+static int32_t volatile g_crtR0Users = 0;
+
+
+/**
+ * Initializes the ring-0 driver runtime library.
+ *
+ * @returns iprt status code.
+ * @param fReserved Flags reserved for the future.
+ */
+RTR0DECL(int) RTR0Init(unsigned fReserved)
+{
+ int rc;
+ uint32_t cNewUsers;
+ Assert(fReserved == 0); RT_NOREF_PV(fReserved);
+#ifndef RT_OS_SOLARIS /* On Solaris our thread preemption information is only obtained in rtR0InitNative().*/
+ RT_ASSERT_PREEMPTIBLE();
+#endif
+
+ /*
+ * The first user initializes it.
+ * We rely on the module loader to ensure that there are no
+ * initialization races should two modules share the IPRT.
+ */
+ cNewUsers = ASMAtomicIncS32(&g_crtR0Users);
+ if (cNewUsers != 1)
+ {
+ if (cNewUsers > 1)
+ return VINF_SUCCESS;
+ ASMAtomicDecS32(&g_crtR0Users);
+ return VERR_INTERNAL_ERROR_3;
+ }
+
+ rc = rtR0InitNative();
+ if (RT_SUCCESS(rc))
+ {
+#ifdef RTR0MEM_WITH_EF_APIS
+ rtR0MemEfInit();
+#endif
+ rc = rtThreadInit();
+ if (RT_SUCCESS(rc))
+ {
+#ifndef IN_GUEST /* play safe for now */
+ rc = rtR0MpNotificationInit();
+ if (RT_SUCCESS(rc))
+ {
+ rc = rtR0PowerNotificationInit();
+ if (RT_SUCCESS(rc))
+ return rc;
+ rtR0MpNotificationTerm();
+ }
+#else
+ if (RT_SUCCESS(rc))
+ return rc;
+#endif
+ rtThreadTerm();
+ }
+#ifdef RTR0MEM_WITH_EF_APIS
+ rtR0MemEfTerm();
+#endif
+ rtR0TermNative();
+ }
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTR0Init);
+
+
+static void rtR0Term(void)
+{
+ rtThreadTerm();
+#ifndef IN_GUEST /* play safe for now */
+ rtR0PowerNotificationTerm();
+ rtR0MpNotificationTerm();
+#endif
+#ifdef RTR0MEM_WITH_EF_APIS
+ rtR0MemEfTerm();
+#endif
+ rtR0TermNative();
+}
+
+
+/**
+ * Terminates the ring-0 driver runtime library.
+ */
+RTR0DECL(void) RTR0Term(void)
+{
+ int32_t cNewUsers;
+ RT_ASSERT_PREEMPTIBLE();
+
+ cNewUsers = ASMAtomicDecS32(&g_crtR0Users);
+ Assert(cNewUsers >= 0);
+ if (cNewUsers == 0)
+ rtR0Term();
+ else if (cNewUsers < 0)
+ ASMAtomicIncS32(&g_crtR0Users);
+}
+RT_EXPORT_SYMBOL(RTR0Term);
+
+
+/* Note! Should *not* be exported since it's only for static linking. */
+RTR0DECL(void) RTR0TermForced(void)
+{
+ RT_ASSERT_PREEMPTIBLE();
+
+ AssertMsg(g_crtR0Users == 1, ("%d\n", g_crtR0Users));
+ ASMAtomicWriteS32(&g_crtR0Users, 0);
+
+ rtR0Term();
+}
+
--- /dev/null
+/* $Id: RTLogWriteDebugger-r0drv-linux.c $ */
+/** @file
+ * IPRT - Log To Debugger, Ring-0 Driver, Linux.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "the-linux-kernel.h"
+#include "internal/iprt.h"
+#include <iprt/log.h>
+
+
+RTDECL(void) RTLogWriteDebugger(const char *pch, size_t cb)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+ printk("%.*s", (int)cb, pch);
+ IPRT_LINUX_RESTORE_EFL_AC();
+}
+RT_EXPORT_SYMBOL(RTLogWriteDebugger);
+
--- /dev/null
+/* $Id: alloc-r0drv-linux.c $ */
+/** @file
+ * IPRT - Memory Allocation, Ring-0 Driver, Linux.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "the-linux-kernel.h"
+#include "internal/iprt.h"
+#include <iprt/mem.h>
+
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include "r0drv/alloc-r0drv.h"
+
+
+#if (defined(RT_ARCH_AMD64) || defined(DOXYGEN_RUNNING)) && !defined(RTMEMALLOC_EXEC_HEAP)
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
+/**
+ * Starting with 2.6.23 we can use __get_vm_area and map_vm_area to allocate
+ * memory in the moduel range. This is preferrable to the exec heap below.
+ */
+# define RTMEMALLOC_EXEC_VM_AREA
+# else
+/**
+ * We need memory in the module range (~2GB to ~0) this can only be obtained
+ * thru APIs that are not exported (see module_alloc()).
+ *
+ * So, we'll have to create a quick and dirty heap here using BSS memory.
+ * Very annoying and it's going to restrict us!
+ */
+# define RTMEMALLOC_EXEC_HEAP
+# endif
+#endif
+
+#ifdef RTMEMALLOC_EXEC_HEAP
+# include <iprt/heap.h>
+# include <iprt/spinlock.h>
+# include <iprt/err.h>
+#endif
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+#ifdef RTMEMALLOC_EXEC_VM_AREA
+/**
+ * Extended header used for headers marked with RTMEMHDR_FLAG_EXEC_VM_AREA.
+ *
+ * This is used with allocating executable memory, for things like generated
+ * code and loaded modules.
+ */
+typedef struct RTMEMLNXHDREX
+{
+ /** The VM area for this allocation. */
+ struct vm_struct *pVmArea;
+ void *pvDummy;
+ /** The header we present to the generic API. */
+ RTMEMHDR Hdr;
+} RTMEMLNXHDREX;
+AssertCompileSize(RTMEMLNXHDREX, 32);
+/** Pointer to an extended memory header. */
+typedef RTMEMLNXHDREX *PRTMEMLNXHDREX;
+#endif
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+#ifdef RTMEMALLOC_EXEC_HEAP
+/** The heap. */
+static RTHEAPSIMPLE g_HeapExec = NIL_RTHEAPSIMPLE;
+/** Spinlock protecting the heap. */
+static RTSPINLOCK g_HeapExecSpinlock = NIL_RTSPINLOCK;
+#endif
+
+
+/**
+ * API for cleaning up the heap spinlock on IPRT termination.
+ * This is as RTMemExecDonate specific to AMD64 Linux/GNU.
+ */
+DECLHIDDEN(void) rtR0MemExecCleanup(void)
+{
+#ifdef RTMEMALLOC_EXEC_HEAP
+ RTSpinlockDestroy(g_HeapExecSpinlock);
+ g_HeapExecSpinlock = NIL_RTSPINLOCK;
+#endif
+}
+
+
+/**
+ * Donate read+write+execute memory to the exec heap.
+ *
+ * This API is specific to AMD64 and Linux/GNU. A kernel module that desires to
+ * use RTMemExecAlloc on AMD64 Linux/GNU will have to donate some statically
+ * allocated memory in the module if it wishes for GCC generated code to work.
+ * GCC can only generate modules that work in the address range ~2GB to ~0
+ * currently.
+ *
+ * The API only accept one single donation.
+ *
+ * @returns IPRT status code.
+ * @retval VERR_NOT_SUPPORTED if the code isn't enabled.
+ * @param pvMemory Pointer to the memory block.
+ * @param cb The size of the memory block.
+ */
+RTR0DECL(int) RTR0MemExecDonate(void *pvMemory, size_t cb)
+{
+#ifdef RTMEMALLOC_EXEC_HEAP
+ int rc;
+ AssertReturn(g_HeapExec == NIL_RTHEAPSIMPLE, VERR_WRONG_ORDER);
+
+ rc = RTSpinlockCreate(&g_HeapExecSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "RTR0MemExecDonate");
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTHeapSimpleInit(&g_HeapExec, pvMemory, cb);
+ if (RT_FAILURE(rc))
+ rtR0MemExecCleanup();
+ }
+ return rc;
+#else
+ RT_NOREF_PV(pvMemory); RT_NOREF_PV(cb);
+ return VERR_NOT_SUPPORTED;
+#endif
+}
+RT_EXPORT_SYMBOL(RTR0MemExecDonate);
+
+
+
+#ifdef RTMEMALLOC_EXEC_VM_AREA
+/**
+ * Allocate executable kernel memory in the module range.
+ *
+ * @returns Pointer to a allocation header success. NULL on failure.
+ *
+ * @param cb The size the user requested.
+ */
+static PRTMEMHDR rtR0MemAllocExecVmArea(size_t cb)
+{
+ size_t const cbAlloc = RT_ALIGN_Z(sizeof(RTMEMLNXHDREX) + cb, PAGE_SIZE);
+ size_t const cPages = cbAlloc >> PAGE_SHIFT;
+ struct page **papPages;
+ struct vm_struct *pVmArea;
+ size_t iPage;
+
+ pVmArea = __get_vm_area(cbAlloc, VM_ALLOC, MODULES_VADDR, MODULES_END);
+ if (!pVmArea)
+ return NULL;
+ pVmArea->nr_pages = 0; /* paranoia? */
+ pVmArea->pages = NULL; /* paranoia? */
+
+ papPages = (struct page **)kmalloc(cPages * sizeof(papPages[0]), GFP_KERNEL | __GFP_NOWARN);
+ if (!papPages)
+ {
+ vunmap(pVmArea->addr);
+ return NULL;
+ }
+
+ for (iPage = 0; iPage < cPages; iPage++)
+ {
+ papPages[iPage] = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_NOWARN);
+ if (!papPages[iPage])
+ break;
+ }
+ if (iPage == cPages)
+ {
+ /*
+ * Map the pages.
+ *
+ * Not entirely sure we really need to set nr_pages and pages here, but
+ * they provide a very convenient place for storing something we need
+ * in the free function, if nothing else...
+ */
+# if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
+ struct page **papPagesIterator = papPages;
+# endif
+ pVmArea->nr_pages = cPages;
+ pVmArea->pages = papPages;
+ if (!map_vm_area(pVmArea, PAGE_KERNEL_EXEC,
+# if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
+ &papPagesIterator
+# else
+ papPages
+# endif
+ ))
+ {
+ PRTMEMLNXHDREX pHdrEx = (PRTMEMLNXHDREX)pVmArea->addr;
+ pHdrEx->pVmArea = pVmArea;
+ pHdrEx->pvDummy = NULL;
+ return &pHdrEx->Hdr;
+ }
+ /* bail out */
+# if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
+ pVmArea->nr_pages = papPagesIterator - papPages;
+# endif
+ }
+
+ vunmap(pVmArea->addr);
+
+ while (iPage-- > 0)
+ __free_page(papPages[iPage]);
+ kfree(papPages);
+
+ return NULL;
+}
+#endif /* RTMEMALLOC_EXEC_VM_AREA */
+
+
+/**
+ * OS specific allocation function.
+ */
+DECLHIDDEN(int) rtR0MemAllocEx(size_t cb, uint32_t fFlags, PRTMEMHDR *ppHdr)
+{
+ PRTMEMHDR pHdr;
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ /*
+ * Allocate.
+ */
+ if (fFlags & RTMEMHDR_FLAG_EXEC)
+ {
+ if (fFlags & RTMEMHDR_FLAG_ANY_CTX)
+ return VERR_NOT_SUPPORTED;
+
+#if defined(RT_ARCH_AMD64)
+# ifdef RTMEMALLOC_EXEC_HEAP
+ if (g_HeapExec != NIL_RTHEAPSIMPLE)
+ {
+ RTSpinlockAcquire(g_HeapExecSpinlock);
+ pHdr = (PRTMEMHDR)RTHeapSimpleAlloc(g_HeapExec, cb + sizeof(*pHdr), 0);
+ RTSpinlockRelease(g_HeapExecSpinlock);
+ fFlags |= RTMEMHDR_FLAG_EXEC_HEAP;
+ }
+ else
+ pHdr = NULL;
+
+# elif defined(RTMEMALLOC_EXEC_VM_AREA)
+ pHdr = rtR0MemAllocExecVmArea(cb);
+ fFlags |= RTMEMHDR_FLAG_EXEC_VM_AREA;
+
+# else /* !RTMEMALLOC_EXEC_HEAP */
+# error "you don not want to go here..."
+ pHdr = (PRTMEMHDR)__vmalloc(cb + sizeof(*pHdr), GFP_KERNEL | __GFP_HIGHMEM | __GFP_NOWARN, MY_PAGE_KERNEL_EXEC);
+# endif /* !RTMEMALLOC_EXEC_HEAP */
+
+#elif defined(PAGE_KERNEL_EXEC) && defined(CONFIG_X86_PAE)
+ pHdr = (PRTMEMHDR)__vmalloc(cb + sizeof(*pHdr), GFP_KERNEL | __GFP_HIGHMEM | __GFP_NOWARN, MY_PAGE_KERNEL_EXEC);
+#else
+ pHdr = (PRTMEMHDR)vmalloc(cb + sizeof(*pHdr));
+#endif
+ }
+ else
+ {
+ if (
+#if 1 /* vmalloc has serious performance issues, avoid it. */
+ cb <= PAGE_SIZE*16 - sizeof(*pHdr)
+#else
+ cb <= PAGE_SIZE
+#endif
+ || (fFlags & RTMEMHDR_FLAG_ANY_CTX)
+ )
+ {
+ fFlags |= RTMEMHDR_FLAG_KMALLOC;
+ pHdr = kmalloc(cb + sizeof(*pHdr),
+ (fFlags & RTMEMHDR_FLAG_ANY_CTX_ALLOC) ? (GFP_ATOMIC | __GFP_NOWARN)
+ : (GFP_KERNEL | __GFP_NOWARN));
+ if (RT_UNLIKELY( !pHdr
+ && cb > PAGE_SIZE
+ && !(fFlags & RTMEMHDR_FLAG_ANY_CTX) ))
+ {
+ fFlags &= ~RTMEMHDR_FLAG_KMALLOC;
+ pHdr = vmalloc(cb + sizeof(*pHdr));
+ }
+ }
+ else
+ pHdr = vmalloc(cb + sizeof(*pHdr));
+ }
+ if (RT_UNLIKELY(!pHdr))
+ {
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VERR_NO_MEMORY;
+ }
+
+ /*
+ * Initialize.
+ */
+ pHdr->u32Magic = RTMEMHDR_MAGIC;
+ pHdr->fFlags = fFlags;
+ pHdr->cb = cb;
+ pHdr->cbReq = cb;
+
+ *ppHdr = pHdr;
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * OS specific free function.
+ */
+DECLHIDDEN(void) rtR0MemFree(PRTMEMHDR pHdr)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ pHdr->u32Magic += 1;
+ if (pHdr->fFlags & RTMEMHDR_FLAG_KMALLOC)
+ kfree(pHdr);
+#ifdef RTMEMALLOC_EXEC_HEAP
+ else if (pHdr->fFlags & RTMEMHDR_FLAG_EXEC_HEAP)
+ {
+ RTSpinlockAcquire(g_HeapExecSpinlock);
+ RTHeapSimpleFree(g_HeapExec, pHdr);
+ RTSpinlockRelease(g_HeapExecSpinlock);
+ }
+#endif
+#ifdef RTMEMALLOC_EXEC_VM_AREA
+ else if (pHdr->fFlags & RTMEMHDR_FLAG_EXEC_VM_AREA)
+ {
+ PRTMEMLNXHDREX pHdrEx = RT_FROM_MEMBER(pHdr, RTMEMLNXHDREX, Hdr);
+ size_t iPage = pHdrEx->pVmArea->nr_pages;
+ struct page **papPages = pHdrEx->pVmArea->pages;
+ void *pvMapping = pHdrEx->pVmArea->addr;
+
+ vunmap(pvMapping);
+
+ while (iPage-- > 0)
+ __free_page(papPages[iPage]);
+ kfree(papPages);
+ }
+#endif
+ else
+ vfree(pHdr);
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+}
+
+
+
+/**
+ * Compute order. Some functions allocate 2^order pages.
+ *
+ * @returns order.
+ * @param cPages Number of pages.
+ */
+static int CalcPowerOf2Order(unsigned long cPages)
+{
+ int iOrder;
+ unsigned long cTmp;
+
+ for (iOrder = 0, cTmp = cPages; cTmp >>= 1; ++iOrder)
+ ;
+ if (cPages & ~(1 << iOrder))
+ ++iOrder;
+
+ return iOrder;
+}
+
+
+/**
+ * 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)
+{
+ int cOrder;
+ unsigned cPages;
+ struct page *paPages;
+ void *pvRet;
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ /*
+ * validate input.
+ */
+ Assert(VALID_PTR(pPhys));
+ Assert(cb > 0);
+
+ /*
+ * Allocate page pointer array.
+ */
+ cb = RT_ALIGN_Z(cb, PAGE_SIZE);
+ cPages = cb >> PAGE_SHIFT;
+ cOrder = CalcPowerOf2Order(cPages);
+#if (defined(RT_ARCH_AMD64) || defined(CONFIG_X86_PAE)) && defined(GFP_DMA32)
+ /* ZONE_DMA32: 0-4GB */
+ paPages = alloc_pages(GFP_DMA32 | __GFP_NOWARN, cOrder);
+ if (!paPages)
+#endif
+#ifdef RT_ARCH_AMD64
+ /* ZONE_DMA; 0-16MB */
+ paPages = alloc_pages(GFP_DMA | __GFP_NOWARN, cOrder);
+#else
+ /* ZONE_NORMAL: 0-896MB */
+ paPages = alloc_pages(GFP_USER | __GFP_NOWARN, cOrder);
+#endif
+ if (paPages)
+ {
+ /*
+ * Reserve the pages and mark them executable.
+ */
+ unsigned iPage;
+ for (iPage = 0; iPage < cPages; iPage++)
+ {
+ Assert(!PageHighMem(&paPages[iPage]));
+ if (iPage + 1 < cPages)
+ {
+ AssertMsg( (uintptr_t)phys_to_virt(page_to_phys(&paPages[iPage])) + PAGE_SIZE
+ == (uintptr_t)phys_to_virt(page_to_phys(&paPages[iPage + 1]))
+ && page_to_phys(&paPages[iPage]) + PAGE_SIZE
+ == page_to_phys(&paPages[iPage + 1]),
+ ("iPage=%i cPages=%u [0]=%#llx,%p [1]=%#llx,%p\n", iPage, cPages,
+ (long long)page_to_phys(&paPages[iPage]), phys_to_virt(page_to_phys(&paPages[iPage])),
+ (long long)page_to_phys(&paPages[iPage + 1]), phys_to_virt(page_to_phys(&paPages[iPage + 1])) ));
+ }
+
+ SetPageReserved(&paPages[iPage]);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 20) /** @todo find the exact kernel where change_page_attr was introduced. */
+ MY_SET_PAGES_EXEC(&paPages[iPage], 1);
+#endif
+ }
+ *pPhys = page_to_phys(paPages);
+ pvRet = phys_to_virt(page_to_phys(paPages));
+ }
+ else
+ pvRet = NULL;
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return pvRet;
+}
+RT_EXPORT_SYMBOL(RTMemContAlloc);
+
+
+/**
+ * Frees memory allocated using RTMemContAlloc().
+ *
+ * @param pv Pointer to return from RTMemContAlloc().
+ * @param cb The cb parameter passed to RTMemContAlloc().
+ */
+RTR0DECL(void) RTMemContFree(void *pv, size_t cb)
+{
+ if (pv)
+ {
+ int cOrder;
+ unsigned cPages;
+ unsigned iPage;
+ struct page *paPages;
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ /* validate */
+ AssertMsg(!((uintptr_t)pv & PAGE_OFFSET_MASK), ("pv=%p\n", pv));
+ Assert(cb > 0);
+
+ /* calc order and get pages */
+ cb = RT_ALIGN_Z(cb, PAGE_SIZE);
+ cPages = cb >> PAGE_SHIFT;
+ cOrder = CalcPowerOf2Order(cPages);
+ paPages = virt_to_page(pv);
+
+ /*
+ * Restore page attributes freeing the pages.
+ */
+ for (iPage = 0; iPage < cPages; iPage++)
+ {
+ ClearPageReserved(&paPages[iPage]);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 20) /** @todo find the exact kernel where change_page_attr was introduced. */
+ MY_SET_PAGES_NOEXEC(&paPages[iPage], 1);
+#endif
+ }
+ __free_pages(paPages, cOrder);
+ IPRT_LINUX_RESTORE_EFL_AC();
+ }
+}
+RT_EXPORT_SYMBOL(RTMemContFree);
+
--- /dev/null
+/* $Id: assert-r0drv-linux.c $ */
+/** @file
+ * IPRT - Assertion Workers, Ring-0 Drivers, Linux.
+ */
+
+/*
+ * Copyright (C) 2007-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "the-linux-kernel.h"
+#include "internal/iprt.h"
+
+#include <iprt/assert.h>
+#include <iprt/log.h>
+#include <iprt/string.h>
+#include <iprt/stdarg.h>
+#include <iprt/asm.h>
+
+#include "internal/assert.h"
+
+
+DECLHIDDEN(void) rtR0AssertNativeMsg1(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+ printk(KERN_EMERG
+ "\r\n!!Assertion Failed!!\r\n"
+ "Expression: %s\r\n"
+ "Location : %s(%d) %s\r\n",
+ pszExpr, pszFile, uLine, pszFunction);
+ IPRT_LINUX_RESTORE_EFL_AC();
+}
+
+
+DECLHIDDEN(void) rtR0AssertNativeMsg2V(bool fInitial, const char *pszFormat, va_list va)
+{
+ char szMsg[256];
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, va);
+ szMsg[sizeof(szMsg) - 1] = '\0';
+ printk(KERN_EMERG "%s", szMsg);
+
+ NOREF(fInitial);
+ IPRT_LINUX_RESTORE_EFL_AC();
+}
+
+
+RTR0DECL(void) RTR0AssertPanicSystem(void)
+{
+ panic("%s%s", g_szRTAssertMsg1, g_szRTAssertMsg2);
+}
+RT_EXPORT_SYMBOL(RTR0AssertPanicSystem);
+
--- /dev/null
+/* $Id: initterm-r0drv-linux.c $ */
+/** @file
+ * IPRT - Initialization & Termination, R0 Driver, Linux.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "the-linux-kernel.h"
+#include "internal/iprt.h"
+#include <iprt/err.h>
+#include <iprt/assert.h>
+#include "internal/initterm.h"
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/** The IPRT work queue. */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 41)
+static struct workqueue_struct *g_prtR0LnxWorkQueue;
+#else
+static DECLARE_TASK_QUEUE(g_rtR0LnxWorkQueue);
+#endif
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+/* in alloc-r0drv0-linux.c */
+DECLHIDDEN(void) rtR0MemExecCleanup(void);
+
+
+/**
+ * Pushes an item onto the IPRT work queue.
+ *
+ * @param pWork The work item.
+ * @param pfnWorker The callback function. It will be called back
+ * with @a pWork as argument.
+ */
+DECLHIDDEN(void) rtR0LnxWorkqueuePush(RTR0LNXWORKQUEUEITEM *pWork, void (*pfnWorker)(RTR0LNXWORKQUEUEITEM *))
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 41)
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
+ INIT_WORK(pWork, pfnWorker);
+# else
+ INIT_WORK(pWork, pfnWorker, pWork);
+# endif
+ queue_work(g_prtR0LnxWorkQueue, pWork);
+#else
+ INIT_TQUEUE(pWork, (void (*)(void *))pfnWorker, pWork);
+ queue_task(pWork, &g_rtR0LnxWorkQueue);
+#endif
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+}
+
+
+/**
+ * Flushes all items in the IPRT work queue.
+ *
+ * @remarks This is mostly for 2.4.x compatability. Must not be called from
+ * atomic contexts or with unncessary locks held.
+ */
+DECLHIDDEN(void) rtR0LnxWorkqueueFlush(void)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 41)
+ flush_workqueue(g_prtR0LnxWorkQueue);
+#else
+ run_task_queue(&g_rtR0LnxWorkQueue);
+#endif
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+}
+
+
+DECLHIDDEN(int) rtR0InitNative(void)
+{
+ int rc = VINF_SUCCESS;
+ IPRT_LINUX_SAVE_EFL_AC();
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 41)
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
+ g_prtR0LnxWorkQueue = create_workqueue("iprt-VBoxWQueue");
+ #else
+ g_prtR0LnxWorkQueue = create_workqueue("iprt-VBoxQ");
+ #endif
+ if (!g_prtR0LnxWorkQueue)
+ rc = VERR_NO_MEMORY;
+#endif
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc;
+}
+
+
+DECLHIDDEN(void) rtR0TermNative(void)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ rtR0LnxWorkqueueFlush();
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 41)
+ destroy_workqueue(g_prtR0LnxWorkQueue);
+ g_prtR0LnxWorkQueue = NULL;
+#endif
+
+ rtR0MemExecCleanup();
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+}
+
--- /dev/null
+/* $Id: memobj-r0drv-linux.c $ */
+/** @file
+ * IPRT - Ring-0 Memory Objects, Linux.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "the-linux-kernel.h"
+
+#include <iprt/memobj.h>
+#include <iprt/alloc.h>
+#include <iprt/assert.h>
+#include <iprt/log.h>
+#include <iprt/process.h>
+#include <iprt/string.h>
+#include "internal/memobj.h"
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/* early 2.6 kernels */
+#ifndef PAGE_SHARED_EXEC
+# define PAGE_SHARED_EXEC PAGE_SHARED
+#endif
+#ifndef PAGE_READONLY_EXEC
+# define PAGE_READONLY_EXEC PAGE_READONLY
+#endif
+
+/*
+ * 2.6.29+ kernels don't work with remap_pfn_range() anymore because
+ * track_pfn_vma_new() is apparently not defined for non-RAM pages.
+ * It should be safe to use vm_insert_page() older kernels as well.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
+# define VBOX_USE_INSERT_PAGE
+#endif
+#if defined(CONFIG_X86_PAE) \
+ && ( defined(HAVE_26_STYLE_REMAP_PAGE_RANGE) \
+ || ( LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) \
+ && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11)))
+# define VBOX_USE_PAE_HACK
+#endif
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * The Darwin version of the memory object structure.
+ */
+typedef struct RTR0MEMOBJLNX
+{
+ /** The core structure. */
+ RTR0MEMOBJINTERNAL Core;
+ /** Set if the allocation is contiguous.
+ * This means it has to be given back as one chunk. */
+ bool fContiguous;
+ /** Set if we've vmap'ed the memory into ring-0. */
+ bool fMappedToRing0;
+ /** The pages in the apPages array. */
+ size_t cPages;
+ /** Array of struct page pointers. (variable size) */
+ struct page *apPages[1];
+} RTR0MEMOBJLNX, *PRTR0MEMOBJLNX;
+
+
+static void rtR0MemObjLinuxFreePages(PRTR0MEMOBJLNX pMemLnx);
+
+
+/**
+ * Helper that converts from a RTR0PROCESS handle to a linux task.
+ *
+ * @returns The corresponding Linux task.
+ * @param R0Process IPRT ring-0 process handle.
+ */
+static struct task_struct *rtR0ProcessToLinuxTask(RTR0PROCESS R0Process)
+{
+ /** @todo fix rtR0ProcessToLinuxTask!! */
+ /** @todo many (all?) callers currently assume that we return 'current'! */
+ return R0Process == RTR0ProcHandleSelf() ? current : NULL;
+}
+
+
+/**
+ * Compute order. Some functions allocate 2^order pages.
+ *
+ * @returns order.
+ * @param cPages Number of pages.
+ */
+static int rtR0MemObjLinuxOrder(size_t cPages)
+{
+ int iOrder;
+ size_t cTmp;
+
+ for (iOrder = 0, cTmp = cPages; cTmp >>= 1; ++iOrder)
+ ;
+ if (cPages & ~((size_t)1 << iOrder))
+ ++iOrder;
+
+ return iOrder;
+}
+
+
+/**
+ * Converts from RTMEM_PROT_* to Linux PAGE_*.
+ *
+ * @returns Linux page protection constant.
+ * @param fProt The IPRT protection mask.
+ * @param fKernel Whether it applies to kernel or user space.
+ */
+static pgprot_t rtR0MemObjLinuxConvertProt(unsigned fProt, bool fKernel)
+{
+ switch (fProt)
+ {
+ default:
+ AssertMsgFailed(("%#x %d\n", fProt, fKernel));
+ case RTMEM_PROT_NONE:
+ return PAGE_NONE;
+
+ case RTMEM_PROT_READ:
+ return fKernel ? PAGE_KERNEL_RO : PAGE_READONLY;
+
+ case RTMEM_PROT_WRITE:
+ case RTMEM_PROT_WRITE | RTMEM_PROT_READ:
+ return fKernel ? PAGE_KERNEL : PAGE_SHARED;
+
+ case RTMEM_PROT_EXEC:
+ case RTMEM_PROT_EXEC | RTMEM_PROT_READ:
+#if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)
+ if (fKernel)
+ {
+ pgprot_t fPg = MY_PAGE_KERNEL_EXEC;
+ pgprot_val(fPg) &= ~_PAGE_RW;
+ return fPg;
+ }
+ return PAGE_READONLY_EXEC;
+#else
+ return fKernel ? MY_PAGE_KERNEL_EXEC : PAGE_READONLY_EXEC;
+#endif
+
+ case RTMEM_PROT_WRITE | RTMEM_PROT_EXEC:
+ case RTMEM_PROT_WRITE | RTMEM_PROT_EXEC | RTMEM_PROT_READ:
+ return fKernel ? MY_PAGE_KERNEL_EXEC : PAGE_SHARED_EXEC;
+ }
+}
+
+
+/**
+ * Worker for rtR0MemObjNativeReserveUser and rtR0MemObjNativerMapUser that creates
+ * an empty user space mapping.
+ *
+ * We acquire the mmap_sem of the task!
+ *
+ * @returns Pointer to the mapping.
+ * (void *)-1 on failure.
+ * @param R3PtrFixed (RTR3PTR)-1 if anywhere, otherwise a specific location.
+ * @param cb The size of the mapping.
+ * @param uAlignment The alignment of the mapping.
+ * @param pTask The Linux task to create this mapping in.
+ * @param fProt The RTMEM_PROT_* mask.
+ */
+static void *rtR0MemObjLinuxDoMmap(RTR3PTR R3PtrFixed, size_t cb, size_t uAlignment, struct task_struct *pTask, unsigned fProt)
+{
+ unsigned fLnxProt;
+ unsigned long ulAddr;
+
+ Assert(pTask == current); /* do_mmap */
+ RT_NOREF_PV(pTask);
+
+ /*
+ * Convert from IPRT protection to mman.h PROT_ and call do_mmap.
+ */
+ fProt &= (RTMEM_PROT_NONE | RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC);
+ if (fProt == RTMEM_PROT_NONE)
+ fLnxProt = PROT_NONE;
+ else
+ {
+ fLnxProt = 0;
+ if (fProt & RTMEM_PROT_READ)
+ fLnxProt |= PROT_READ;
+ if (fProt & RTMEM_PROT_WRITE)
+ fLnxProt |= PROT_WRITE;
+ if (fProt & RTMEM_PROT_EXEC)
+ fLnxProt |= PROT_EXEC;
+ }
+
+ if (R3PtrFixed != (RTR3PTR)-1)
+ {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+ ulAddr = vm_mmap(NULL, R3PtrFixed, cb, fLnxProt, MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, 0);
+#else
+ down_write(&pTask->mm->mmap_sem);
+ ulAddr = do_mmap(NULL, R3PtrFixed, cb, fLnxProt, MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, 0);
+ up_write(&pTask->mm->mmap_sem);
+#endif
+ }
+ else
+ {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+ ulAddr = vm_mmap(NULL, 0, cb, fLnxProt, MAP_SHARED | MAP_ANONYMOUS, 0);
+#else
+ down_write(&pTask->mm->mmap_sem);
+ ulAddr = do_mmap(NULL, 0, cb, fLnxProt, MAP_SHARED | MAP_ANONYMOUS, 0);
+ up_write(&pTask->mm->mmap_sem);
+#endif
+ if ( !(ulAddr & ~PAGE_MASK)
+ && (ulAddr & (uAlignment - 1)))
+ {
+ /** @todo implement uAlignment properly... We'll probably need to make some dummy mappings to fill
+ * up alignment gaps. This is of course complicated by fragmentation (which we might have cause
+ * ourselves) and further by there begin two mmap strategies (top / bottom). */
+ /* For now, just ignore uAlignment requirements... */
+ }
+ }
+
+
+ if (ulAddr & ~PAGE_MASK) /* ~PAGE_MASK == PAGE_OFFSET_MASK */
+ return (void *)-1;
+ return (void *)ulAddr;
+}
+
+
+/**
+ * Worker that destroys a user space mapping.
+ * Undoes what rtR0MemObjLinuxDoMmap did.
+ *
+ * We acquire the mmap_sem of the task!
+ *
+ * @param pv The ring-3 mapping.
+ * @param cb The size of the mapping.
+ * @param pTask The Linux task to destroy this mapping in.
+ */
+static void rtR0MemObjLinuxDoMunmap(void *pv, size_t cb, struct task_struct *pTask)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+ Assert(pTask == current); RT_NOREF_PV(pTask);
+ vm_munmap((unsigned long)pv, cb);
+#elif defined(USE_RHEL4_MUNMAP)
+ down_write(&pTask->mm->mmap_sem);
+ do_munmap(pTask->mm, (unsigned long)pv, cb, 0); /* should it be 1 or 0? */
+ up_write(&pTask->mm->mmap_sem);
+#else
+ down_write(&pTask->mm->mmap_sem);
+ do_munmap(pTask->mm, (unsigned long)pv, cb);
+ up_write(&pTask->mm->mmap_sem);
+#endif
+}
+
+
+/**
+ * Internal worker that allocates physical pages and creates the memory object for them.
+ *
+ * @returns IPRT status code.
+ * @param ppMemLnx Where to store the memory object pointer.
+ * @param enmType The object type.
+ * @param cb The number of bytes to allocate.
+ * @param uAlignment The alignment of the physical memory.
+ * Only valid if fContiguous == true, ignored otherwise.
+ * @param fFlagsLnx The page allocation flags (GPFs).
+ * @param fContiguous Whether the allocation must be contiguous.
+ * @param rcNoMem What to return when we're out of pages.
+ */
+static int rtR0MemObjLinuxAllocPages(PRTR0MEMOBJLNX *ppMemLnx, RTR0MEMOBJTYPE enmType, size_t cb,
+ size_t uAlignment, unsigned fFlagsLnx, bool fContiguous, int rcNoMem)
+{
+ size_t iPage;
+ size_t const cPages = cb >> PAGE_SHIFT;
+ struct page *paPages;
+
+ /*
+ * Allocate a memory object structure that's large enough to contain
+ * the page pointer array.
+ */
+ PRTR0MEMOBJLNX pMemLnx = (PRTR0MEMOBJLNX)rtR0MemObjNew(RT_OFFSETOF(RTR0MEMOBJLNX, apPages[cPages]), enmType, NULL, cb);
+ if (!pMemLnx)
+ return VERR_NO_MEMORY;
+ pMemLnx->cPages = cPages;
+
+ if (cPages > 255)
+ {
+# ifdef __GFP_REPEAT
+ /* Try hard to allocate the memory, but the allocation attempt might fail. */
+ fFlagsLnx |= __GFP_REPEAT;
+# endif
+# ifdef __GFP_NOMEMALLOC
+ /* Introduced with Linux 2.6.12: Don't use emergency reserves */
+ fFlagsLnx |= __GFP_NOMEMALLOC;
+# endif
+ }
+
+ /*
+ * Allocate the pages.
+ * For small allocations we'll try contiguous first and then fall back on page by page.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 22)
+ if ( fContiguous
+ || cb <= PAGE_SIZE * 2)
+ {
+# ifdef VBOX_USE_INSERT_PAGE
+ paPages = alloc_pages(fFlagsLnx | __GFP_COMP | __GFP_NOWARN, rtR0MemObjLinuxOrder(cPages));
+# else
+ paPages = alloc_pages(fFlagsLnx | __GFP_NOWARN, rtR0MemObjLinuxOrder(cPages));
+# endif
+ if (paPages)
+ {
+ fContiguous = true;
+ for (iPage = 0; iPage < cPages; iPage++)
+ pMemLnx->apPages[iPage] = &paPages[iPage];
+ }
+ else if (fContiguous)
+ {
+ rtR0MemObjDelete(&pMemLnx->Core);
+ return rcNoMem;
+ }
+ }
+
+ if (!fContiguous)
+ {
+ for (iPage = 0; iPage < cPages; iPage++)
+ {
+ pMemLnx->apPages[iPage] = alloc_page(fFlagsLnx | __GFP_NOWARN);
+ if (RT_UNLIKELY(!pMemLnx->apPages[iPage]))
+ {
+ while (iPage-- > 0)
+ __free_page(pMemLnx->apPages[iPage]);
+ rtR0MemObjDelete(&pMemLnx->Core);
+ return rcNoMem;
+ }
+ }
+ }
+
+#else /* < 2.4.22 */
+ /** @todo figure out why we didn't allocate page-by-page on 2.4.21 and older... */
+ paPages = alloc_pages(fFlagsLnx, rtR0MemObjLinuxOrder(cPages));
+ if (!paPages)
+ {
+ rtR0MemObjDelete(&pMemLnx->Core);
+ return rcNoMem;
+ }
+ for (iPage = 0; iPage < cPages; iPage++)
+ {
+ pMemLnx->apPages[iPage] = &paPages[iPage];
+ MY_SET_PAGES_EXEC(pMemLnx->apPages[iPage], 1);
+ if (PageHighMem(pMemLnx->apPages[iPage]))
+ BUG();
+ }
+
+ fContiguous = true;
+#endif /* < 2.4.22 */
+ pMemLnx->fContiguous = fContiguous;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0)
+ /*
+ * Reserve the pages.
+ *
+ * Linux >= 4.5 with CONFIG_DEBUG_VM panics when setting PG_reserved on compound
+ * pages. According to Michal Hocko this shouldn't be necessary anyway because
+ * as pages which are not on the LRU list are never evictable.
+ */
+ for (iPage = 0; iPage < cPages; iPage++)
+ SetPageReserved(pMemLnx->apPages[iPage]);
+#endif
+
+ /*
+ * Note that the physical address of memory allocated with alloc_pages(flags, order)
+ * is always 2^(PAGE_SHIFT+order)-aligned.
+ */
+ if ( fContiguous
+ && uAlignment > PAGE_SIZE)
+ {
+ /*
+ * Check for alignment constraints. The physical address of memory allocated with
+ * alloc_pages(flags, order) is always 2^(PAGE_SHIFT+order)-aligned.
+ */
+ if (RT_UNLIKELY(page_to_phys(pMemLnx->apPages[0]) & (uAlignment - 1)))
+ {
+ /*
+ * This should never happen!
+ */
+ printk("rtR0MemObjLinuxAllocPages(cb=0x%lx, uAlignment=0x%lx): alloc_pages(..., %d) returned physical memory at 0x%lx!\n",
+ (unsigned long)cb, (unsigned long)uAlignment, rtR0MemObjLinuxOrder(cPages), (unsigned long)page_to_phys(pMemLnx->apPages[0]));
+ rtR0MemObjLinuxFreePages(pMemLnx);
+ return rcNoMem;
+ }
+ }
+
+ *ppMemLnx = pMemLnx;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Frees the physical pages allocated by the rtR0MemObjLinuxAllocPages() call.
+ *
+ * This method does NOT free the object.
+ *
+ * @param pMemLnx The object which physical pages should be freed.
+ */
+static void rtR0MemObjLinuxFreePages(PRTR0MEMOBJLNX pMemLnx)
+{
+ size_t iPage = pMemLnx->cPages;
+ if (iPage > 0)
+ {
+ /*
+ * Restore the page flags.
+ */
+ while (iPage-- > 0)
+ {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0)
+ /*
+ * See SetPageReserved() in rtR0MemObjLinuxAllocPages()
+ */
+ ClearPageReserved(pMemLnx->apPages[iPage]);
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 22)
+#else
+ MY_SET_PAGES_NOEXEC(pMemLnx->apPages[iPage], 1);
+#endif
+ }
+
+ /*
+ * Free the pages.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 22)
+ if (!pMemLnx->fContiguous)
+ {
+ iPage = pMemLnx->cPages;
+ while (iPage-- > 0)
+ __free_page(pMemLnx->apPages[iPage]);
+ }
+ else
+#endif
+ __free_pages(pMemLnx->apPages[0], rtR0MemObjLinuxOrder(pMemLnx->cPages));
+
+ pMemLnx->cPages = 0;
+ }
+}
+
+
+/**
+ * Maps the allocation into ring-0.
+ *
+ * This will update the RTR0MEMOBJLNX::Core.pv and RTR0MEMOBJ::fMappedToRing0 members.
+ *
+ * Contiguous mappings that isn't in 'high' memory will already be mapped into kernel
+ * space, so we'll use that mapping if possible. If execute access is required, we'll
+ * play safe and do our own mapping.
+ *
+ * @returns IPRT status code.
+ * @param pMemLnx The linux memory object to map.
+ * @param fExecutable Whether execute access is required.
+ */
+static int rtR0MemObjLinuxVMap(PRTR0MEMOBJLNX pMemLnx, bool fExecutable)
+{
+ int rc = VINF_SUCCESS;
+
+ /*
+ * Choose mapping strategy.
+ */
+ bool fMustMap = fExecutable
+ || !pMemLnx->fContiguous;
+ if (!fMustMap)
+ {
+ size_t iPage = pMemLnx->cPages;
+ while (iPage-- > 0)
+ if (PageHighMem(pMemLnx->apPages[iPage]))
+ {
+ fMustMap = true;
+ break;
+ }
+ }
+
+ Assert(!pMemLnx->Core.pv);
+ Assert(!pMemLnx->fMappedToRing0);
+
+ if (fMustMap)
+ {
+ /*
+ * Use vmap - 2.4.22 and later.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 22)
+ pgprot_t fPg;
+ pgprot_val(fPg) = _PAGE_PRESENT | _PAGE_RW;
+# ifdef _PAGE_NX
+ if (!fExecutable)
+ pgprot_val(fPg) |= _PAGE_NX;
+# endif
+
+# ifdef VM_MAP
+ pMemLnx->Core.pv = vmap(&pMemLnx->apPages[0], pMemLnx->cPages, VM_MAP, fPg);
+# else
+ pMemLnx->Core.pv = vmap(&pMemLnx->apPages[0], pMemLnx->cPages, VM_ALLOC, fPg);
+# endif
+ if (pMemLnx->Core.pv)
+ pMemLnx->fMappedToRing0 = true;
+ else
+ rc = VERR_MAP_FAILED;
+#else /* < 2.4.22 */
+ rc = VERR_NOT_SUPPORTED;
+#endif
+ }
+ else
+ {
+ /*
+ * Use the kernel RAM mapping.
+ */
+ pMemLnx->Core.pv = phys_to_virt(page_to_phys(pMemLnx->apPages[0]));
+ Assert(pMemLnx->Core.pv);
+ }
+
+ return rc;
+}
+
+
+/**
+ * Undoes what rtR0MemObjLinuxVMap() did.
+ *
+ * @param pMemLnx The linux memory object.
+ */
+static void rtR0MemObjLinuxVUnmap(PRTR0MEMOBJLNX pMemLnx)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 22)
+ if (pMemLnx->fMappedToRing0)
+ {
+ Assert(pMemLnx->Core.pv);
+ vunmap(pMemLnx->Core.pv);
+ pMemLnx->fMappedToRing0 = false;
+ }
+#else /* < 2.4.22 */
+ Assert(!pMemLnx->fMappedToRing0);
+#endif
+ pMemLnx->Core.pv = NULL;
+}
+
+
+DECLHIDDEN(int) rtR0MemObjNativeFree(RTR0MEMOBJ pMem)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+ PRTR0MEMOBJLNX pMemLnx = (PRTR0MEMOBJLNX)pMem;
+
+ /*
+ * Release any memory that we've allocated or locked.
+ */
+ switch (pMemLnx->Core.enmType)
+ {
+ case RTR0MEMOBJTYPE_LOW:
+ case RTR0MEMOBJTYPE_PAGE:
+ case RTR0MEMOBJTYPE_CONT:
+ case RTR0MEMOBJTYPE_PHYS:
+ case RTR0MEMOBJTYPE_PHYS_NC:
+ rtR0MemObjLinuxVUnmap(pMemLnx);
+ rtR0MemObjLinuxFreePages(pMemLnx);
+ break;
+
+ case RTR0MEMOBJTYPE_LOCK:
+ if (pMemLnx->Core.u.Lock.R0Process != NIL_RTR0PROCESS)
+ {
+ struct task_struct *pTask = rtR0ProcessToLinuxTask(pMemLnx->Core.u.Lock.R0Process);
+ size_t iPage;
+ Assert(pTask);
+ if (pTask && pTask->mm)
+ down_read(&pTask->mm->mmap_sem);
+
+ iPage = pMemLnx->cPages;
+ while (iPage-- > 0)
+ {
+ if (!PageReserved(pMemLnx->apPages[iPage]))
+ SetPageDirty(pMemLnx->apPages[iPage]);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0)
+ put_page(pMemLnx->apPages[iPage]);
+#else
+ page_cache_release(pMemLnx->apPages[iPage]);
+#endif
+ }
+
+ if (pTask && pTask->mm)
+ up_read(&pTask->mm->mmap_sem);
+ }
+ /* else: kernel memory - nothing to do here. */
+ break;
+
+ case RTR0MEMOBJTYPE_RES_VIRT:
+ Assert(pMemLnx->Core.pv);
+ if (pMemLnx->Core.u.ResVirt.R0Process != NIL_RTR0PROCESS)
+ {
+ struct task_struct *pTask = rtR0ProcessToLinuxTask(pMemLnx->Core.u.Lock.R0Process);
+ Assert(pTask);
+ if (pTask && pTask->mm)
+ rtR0MemObjLinuxDoMunmap(pMemLnx->Core.pv, pMemLnx->Core.cb, pTask);
+ }
+ else
+ {
+ vunmap(pMemLnx->Core.pv);
+
+ Assert(pMemLnx->cPages == 1 && pMemLnx->apPages[0] != NULL);
+ __free_page(pMemLnx->apPages[0]);
+ pMemLnx->apPages[0] = NULL;
+ pMemLnx->cPages = 0;
+ }
+ pMemLnx->Core.pv = NULL;
+ break;
+
+ case RTR0MEMOBJTYPE_MAPPING:
+ Assert(pMemLnx->cPages == 0); Assert(pMemLnx->Core.pv);
+ if (pMemLnx->Core.u.ResVirt.R0Process != NIL_RTR0PROCESS)
+ {
+ struct task_struct *pTask = rtR0ProcessToLinuxTask(pMemLnx->Core.u.Lock.R0Process);
+ Assert(pTask);
+ if (pTask && pTask->mm)
+ rtR0MemObjLinuxDoMunmap(pMemLnx->Core.pv, pMemLnx->Core.cb, pTask);
+ }
+ else
+ vunmap(pMemLnx->Core.pv);
+ pMemLnx->Core.pv = NULL;
+ break;
+
+ default:
+ AssertMsgFailed(("enmType=%d\n", pMemLnx->Core.enmType));
+ return VERR_INTERNAL_ERROR;
+ }
+ IPRT_LINUX_RESTORE_EFL_ONLY_AC();
+ return VINF_SUCCESS;
+}
+
+
+DECLHIDDEN(int) rtR0MemObjNativeAllocPage(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+ PRTR0MEMOBJLNX pMemLnx;
+ int rc;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 22)
+ rc = rtR0MemObjLinuxAllocPages(&pMemLnx, RTR0MEMOBJTYPE_PAGE, cb, PAGE_SIZE, GFP_HIGHUSER,
+ false /* non-contiguous */, VERR_NO_MEMORY);
+#else
+ rc = rtR0MemObjLinuxAllocPages(&pMemLnx, RTR0MEMOBJTYPE_PAGE, cb, PAGE_SIZE, GFP_USER,
+ false /* non-contiguous */, VERR_NO_MEMORY);
+#endif
+ if (RT_SUCCESS(rc))
+ {
+ rc = rtR0MemObjLinuxVMap(pMemLnx, fExecutable);
+ if (RT_SUCCESS(rc))
+ {
+ *ppMem = &pMemLnx->Core;
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc;
+ }
+
+ rtR0MemObjLinuxFreePages(pMemLnx);
+ rtR0MemObjDelete(&pMemLnx->Core);
+ }
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc;
+}
+
+
+DECLHIDDEN(int) rtR0MemObjNativeAllocLow(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+ PRTR0MEMOBJLNX pMemLnx;
+ int rc;
+
+ /* Try to avoid GFP_DMA. GFM_DMA32 was introduced with Linux 2.6.15. */
+#if (defined(RT_ARCH_AMD64) || defined(CONFIG_X86_PAE)) && defined(GFP_DMA32)
+ /* ZONE_DMA32: 0-4GB */
+ rc = rtR0MemObjLinuxAllocPages(&pMemLnx, RTR0MEMOBJTYPE_LOW, cb, PAGE_SIZE, GFP_DMA32,
+ false /* non-contiguous */, VERR_NO_LOW_MEMORY);
+ if (RT_FAILURE(rc))
+#endif
+#ifdef RT_ARCH_AMD64
+ /* ZONE_DMA: 0-16MB */
+ rc = rtR0MemObjLinuxAllocPages(&pMemLnx, RTR0MEMOBJTYPE_LOW, cb, PAGE_SIZE, GFP_DMA,
+ false /* non-contiguous */, VERR_NO_LOW_MEMORY);
+#else
+# ifdef CONFIG_X86_PAE
+# endif
+ /* ZONE_NORMAL: 0-896MB */
+ rc = rtR0MemObjLinuxAllocPages(&pMemLnx, RTR0MEMOBJTYPE_LOW, cb, PAGE_SIZE, GFP_USER,
+ false /* non-contiguous */, VERR_NO_LOW_MEMORY);
+#endif
+ if (RT_SUCCESS(rc))
+ {
+ rc = rtR0MemObjLinuxVMap(pMemLnx, fExecutable);
+ if (RT_SUCCESS(rc))
+ {
+ *ppMem = &pMemLnx->Core;
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc;
+ }
+
+ rtR0MemObjLinuxFreePages(pMemLnx);
+ rtR0MemObjDelete(&pMemLnx->Core);
+ }
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc;
+}
+
+
+DECLHIDDEN(int) rtR0MemObjNativeAllocCont(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+ PRTR0MEMOBJLNX pMemLnx;
+ int rc;
+
+#if (defined(RT_ARCH_AMD64) || defined(CONFIG_X86_PAE)) && defined(GFP_DMA32)
+ /* ZONE_DMA32: 0-4GB */
+ rc = rtR0MemObjLinuxAllocPages(&pMemLnx, RTR0MEMOBJTYPE_CONT, cb, PAGE_SIZE, GFP_DMA32,
+ true /* contiguous */, VERR_NO_CONT_MEMORY);
+ if (RT_FAILURE(rc))
+#endif
+#ifdef RT_ARCH_AMD64
+ /* ZONE_DMA: 0-16MB */
+ rc = rtR0MemObjLinuxAllocPages(&pMemLnx, RTR0MEMOBJTYPE_CONT, cb, PAGE_SIZE, GFP_DMA,
+ true /* contiguous */, VERR_NO_CONT_MEMORY);
+#else
+ /* ZONE_NORMAL (32-bit hosts): 0-896MB */
+ rc = rtR0MemObjLinuxAllocPages(&pMemLnx, RTR0MEMOBJTYPE_CONT, cb, PAGE_SIZE, GFP_USER,
+ true /* contiguous */, VERR_NO_CONT_MEMORY);
+#endif
+ if (RT_SUCCESS(rc))
+ {
+ rc = rtR0MemObjLinuxVMap(pMemLnx, fExecutable);
+ if (RT_SUCCESS(rc))
+ {
+#if defined(RT_STRICT) && (defined(RT_ARCH_AMD64) || defined(CONFIG_HIGHMEM64G))
+ size_t iPage = pMemLnx->cPages;
+ while (iPage-- > 0)
+ Assert(page_to_phys(pMemLnx->apPages[iPage]) < _4G);
+#endif
+ pMemLnx->Core.u.Cont.Phys = page_to_phys(pMemLnx->apPages[0]);
+ *ppMem = &pMemLnx->Core;
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc;
+ }
+
+ rtR0MemObjLinuxFreePages(pMemLnx);
+ rtR0MemObjDelete(&pMemLnx->Core);
+ }
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc;
+}
+
+
+/**
+ * Worker for rtR0MemObjLinuxAllocPhysSub that tries one allocation strategy.
+ *
+ * @returns IPRT status code.
+ * @param ppMemLnx Where to
+ * @param enmType The object type.
+ * @param cb The size of the allocation.
+ * @param uAlignment The alignment of the physical memory.
+ * Only valid for fContiguous == true, ignored otherwise.
+ * @param PhysHighest See rtR0MemObjNativeAllocPhys.
+ * @param fGfp The Linux GFP flags to use for the allocation.
+ */
+static int rtR0MemObjLinuxAllocPhysSub2(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJTYPE enmType,
+ size_t cb, size_t uAlignment, RTHCPHYS PhysHighest, unsigned fGfp)
+{
+ PRTR0MEMOBJLNX pMemLnx;
+ int rc;
+
+ rc = rtR0MemObjLinuxAllocPages(&pMemLnx, enmType, cb, uAlignment, fGfp,
+ enmType == RTR0MEMOBJTYPE_PHYS /* contiguous / non-contiguous */,
+ VERR_NO_PHYS_MEMORY);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /*
+ * Check the addresses if necessary. (Can be optimized a bit for PHYS.)
+ */
+ if (PhysHighest != NIL_RTHCPHYS)
+ {
+ size_t iPage = pMemLnx->cPages;
+ while (iPage-- > 0)
+ if (page_to_phys(pMemLnx->apPages[iPage]) > PhysHighest)
+ {
+ rtR0MemObjLinuxFreePages(pMemLnx);
+ rtR0MemObjDelete(&pMemLnx->Core);
+ return VERR_NO_MEMORY;
+ }
+ }
+
+ /*
+ * Complete the object.
+ */
+ if (enmType == RTR0MEMOBJTYPE_PHYS)
+ {
+ pMemLnx->Core.u.Phys.PhysBase = page_to_phys(pMemLnx->apPages[0]);
+ pMemLnx->Core.u.Phys.fAllocated = true;
+ }
+ *ppMem = &pMemLnx->Core;
+ return rc;
+}
+
+
+/**
+ * Worker for rtR0MemObjNativeAllocPhys and rtR0MemObjNativeAllocPhysNC.
+ *
+ * @returns IPRT status code.
+ * @param ppMem Where to store the memory object pointer on success.
+ * @param enmType The object type.
+ * @param cb The size of the allocation.
+ * @param uAlignment The alignment of the physical memory.
+ * Only valid for enmType == RTR0MEMOBJTYPE_PHYS, ignored otherwise.
+ * @param PhysHighest See rtR0MemObjNativeAllocPhys.
+ */
+static int rtR0MemObjLinuxAllocPhysSub(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJTYPE enmType,
+ size_t cb, size_t uAlignment, RTHCPHYS PhysHighest)
+{
+ int rc;
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ /*
+ * There are two clear cases and that's the <=16MB and anything-goes ones.
+ * When the physical address limit is somewhere in-between those two we'll
+ * just have to try, starting with HIGHUSER and working our way thru the
+ * different types, hoping we'll get lucky.
+ *
+ * We should probably move this physical address restriction logic up to
+ * the page alloc function as it would be more efficient there. But since
+ * we don't expect this to be a performance issue just yet it can wait.
+ */
+ if (PhysHighest == NIL_RTHCPHYS)
+ /* ZONE_HIGHMEM: the whole physical memory */
+ rc = rtR0MemObjLinuxAllocPhysSub2(ppMem, enmType, cb, uAlignment, PhysHighest, GFP_HIGHUSER);
+ else if (PhysHighest <= _1M * 16)
+ /* ZONE_DMA: 0-16MB */
+ rc = rtR0MemObjLinuxAllocPhysSub2(ppMem, enmType, cb, uAlignment, PhysHighest, GFP_DMA);
+ else
+ {
+ rc = VERR_NO_MEMORY;
+ if (RT_FAILURE(rc))
+ /* ZONE_HIGHMEM: the whole physical memory */
+ rc = rtR0MemObjLinuxAllocPhysSub2(ppMem, enmType, cb, uAlignment, PhysHighest, GFP_HIGHUSER);
+ if (RT_FAILURE(rc))
+ /* ZONE_NORMAL: 0-896MB */
+ rc = rtR0MemObjLinuxAllocPhysSub2(ppMem, enmType, cb, uAlignment, PhysHighest, GFP_USER);
+#ifdef GFP_DMA32
+ if (RT_FAILURE(rc))
+ /* ZONE_DMA32: 0-4GB */
+ rc = rtR0MemObjLinuxAllocPhysSub2(ppMem, enmType, cb, uAlignment, PhysHighest, GFP_DMA32);
+#endif
+ if (RT_FAILURE(rc))
+ /* ZONE_DMA: 0-16MB */
+ rc = rtR0MemObjLinuxAllocPhysSub2(ppMem, enmType, cb, uAlignment, PhysHighest, GFP_DMA);
+ }
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc;
+}
+
+
+/**
+ * Translates a kernel virtual address to a linux page structure by walking the
+ * page tables.
+ *
+ * @note We do assume that the page tables will not change as we are walking
+ * them. This assumption is rather forced by the fact that I could not
+ * immediately see any way of preventing this from happening. So, we
+ * take some extra care when accessing them.
+ *
+ * Because of this, we don't want to use this function on memory where
+ * attribute changes to nearby pages is likely to cause large pages to
+ * be used or split up. So, don't use this for the linear mapping of
+ * physical memory.
+ *
+ * @returns Pointer to the page structur or NULL if it could not be found.
+ * @param pv The kernel virtual address.
+ */
+static struct page *rtR0MemObjLinuxVirtToPage(void *pv)
+{
+ unsigned long ulAddr = (unsigned long)pv;
+ unsigned long pfn;
+ struct page *pPage;
+ pte_t *pEntry;
+ union
+ {
+ pgd_t Global;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
+ p4d_t Four;
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
+ pud_t Upper;
+#endif
+ pmd_t Middle;
+ pte_t Entry;
+ } u;
+
+ /* Should this happen in a situation this code will be called in? And if
+ * so, can it change under our feet? See also
+ * "Documentation/vm/active_mm.txt" in the kernel sources. */
+ if (RT_UNLIKELY(!current->active_mm))
+ return NULL;
+ u.Global = *pgd_offset(current->active_mm, ulAddr);
+ if (RT_UNLIKELY(pgd_none(u.Global)))
+ return NULL;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
+ u.Four = *p4d_offset(&u.Global, ulAddr);
+ if (RT_UNLIKELY(p4d_none(u.Four)))
+ return NULL;
+ if (p4d_large(u.Four))
+ {
+ pPage = p4d_page(u.Four);
+ AssertReturn(pPage, NULL);
+ pfn = page_to_pfn(pPage); /* doing the safe way... */
+ AssertCompile(P4D_SHIFT - PAGE_SHIFT < 31);
+ pfn += (ulAddr >> PAGE_SHIFT) & ((UINT32_C(1) << (P4D_SHIFT - PAGE_SHIFT)) - 1);
+ return pfn_to_page(pfn);
+ }
+ u.Upper = *pud_offset(&u.Four, ulAddr);
+# else /* < 4.12 */
+ u.Upper = *pud_offset(&u.Global, ulAddr);
+# endif /* < 4.12 */
+ if (RT_UNLIKELY(pud_none(u.Upper)))
+ return NULL;
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
+ if (pud_large(u.Upper))
+ {
+ pPage = pud_page(u.Upper);
+ AssertReturn(pPage, NULL);
+ pfn = page_to_pfn(pPage); /* doing the safe way... */
+ pfn += (ulAddr >> PAGE_SHIFT) & ((UINT32_C(1) << (PUD_SHIFT - PAGE_SHIFT)) - 1);
+ return pfn_to_page(pfn);
+ }
+# endif
+ u.Middle = *pmd_offset(&u.Upper, ulAddr);
+#else /* < 2.6.11 */
+ u.Middle = *pmd_offset(&u.Global, ulAddr);
+#endif /* < 2.6.11 */
+ if (RT_UNLIKELY(pmd_none(u.Middle)))
+ return NULL;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+ if (pmd_large(u.Middle))
+ {
+ pPage = pmd_page(u.Middle);
+ AssertReturn(pPage, NULL);
+ pfn = page_to_pfn(pPage); /* doing the safe way... */
+ pfn += (ulAddr >> PAGE_SHIFT) & ((UINT32_C(1) << (PMD_SHIFT - PAGE_SHIFT)) - 1);
+ return pfn_to_page(pfn);
+ }
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 5) || defined(pte_offset_map) /* As usual, RHEL 3 had pte_offset_map earlier. */
+ pEntry = pte_offset_map(&u.Middle, ulAddr);
+#else
+ pEntry = pte_offset(&u.Middle, ulAddr);
+#endif
+ if (RT_UNLIKELY(!pEntry))
+ return NULL;
+ u.Entry = *pEntry;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 5) || defined(pte_offset_map)
+ pte_unmap(pEntry);
+#endif
+
+ if (RT_UNLIKELY(!pte_present(u.Entry)))
+ return NULL;
+ return pte_page(u.Entry);
+}
+
+
+DECLHIDDEN(int) rtR0MemObjNativeAllocPhys(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, RTHCPHYS PhysHighest, size_t uAlignment)
+{
+ return rtR0MemObjLinuxAllocPhysSub(ppMem, RTR0MEMOBJTYPE_PHYS, cb, uAlignment, PhysHighest);
+}
+
+
+DECLHIDDEN(int) rtR0MemObjNativeAllocPhysNC(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, RTHCPHYS PhysHighest)
+{
+ return rtR0MemObjLinuxAllocPhysSub(ppMem, RTR0MEMOBJTYPE_PHYS_NC, cb, PAGE_SIZE, PhysHighest);
+}
+
+
+DECLHIDDEN(int) rtR0MemObjNativeEnterPhys(PPRTR0MEMOBJINTERNAL ppMem, RTHCPHYS Phys, size_t cb, uint32_t uCachePolicy)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ /*
+ * All we need to do here is to validate that we can use
+ * ioremap on the specified address (32/64-bit dma_addr_t).
+ */
+ PRTR0MEMOBJLNX pMemLnx;
+ dma_addr_t PhysAddr = Phys;
+ AssertMsgReturn(PhysAddr == Phys, ("%#llx\n", (unsigned long long)Phys), VERR_ADDRESS_TOO_BIG);
+
+ pMemLnx = (PRTR0MEMOBJLNX)rtR0MemObjNew(sizeof(*pMemLnx), RTR0MEMOBJTYPE_PHYS, NULL, cb);
+ if (!pMemLnx)
+ {
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VERR_NO_MEMORY;
+ }
+
+ pMemLnx->Core.u.Phys.PhysBase = PhysAddr;
+ pMemLnx->Core.u.Phys.fAllocated = false;
+ pMemLnx->Core.u.Phys.uCachePolicy = uCachePolicy;
+ Assert(!pMemLnx->cPages);
+ *ppMem = &pMemLnx->Core;
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+}
+
+/* openSUSE Leap 42.3 detection :-/ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) \
+ && LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0) \
+ && defined(FAULT_FLAG_REMOTE)
+# define GET_USER_PAGES_API KERNEL_VERSION(4, 10, 0) /* no typo! */
+#else
+# define GET_USER_PAGES_API LINUX_VERSION_CODE
+#endif
+
+DECLHIDDEN(int) rtR0MemObjNativeLockUser(PPRTR0MEMOBJINTERNAL ppMem, RTR3PTR R3Ptr, size_t cb, uint32_t fAccess, RTR0PROCESS R0Process)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+ const int cPages = cb >> PAGE_SHIFT;
+ struct task_struct *pTask = rtR0ProcessToLinuxTask(R0Process);
+ struct vm_area_struct **papVMAs;
+ PRTR0MEMOBJLNX pMemLnx;
+ int rc = VERR_NO_MEMORY;
+ int const fWrite = fAccess & RTMEM_PROT_WRITE ? 1 : 0;
+
+ /*
+ * Check for valid task and size overflows.
+ */
+ if (!pTask)
+ return VERR_NOT_SUPPORTED;
+ if (((size_t)cPages << PAGE_SHIFT) != cb)
+ return VERR_OUT_OF_RANGE;
+
+ /*
+ * Allocate the memory object and a temporary buffer for the VMAs.
+ */
+ pMemLnx = (PRTR0MEMOBJLNX)rtR0MemObjNew(RT_OFFSETOF(RTR0MEMOBJLNX, apPages[cPages]), RTR0MEMOBJTYPE_LOCK, (void *)R3Ptr, cb);
+ if (!pMemLnx)
+ {
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VERR_NO_MEMORY;
+ }
+
+ papVMAs = (struct vm_area_struct **)RTMemAlloc(sizeof(*papVMAs) * cPages);
+ if (papVMAs)
+ {
+ down_read(&pTask->mm->mmap_sem);
+
+ /*
+ * Get user pages.
+ */
+#if GET_USER_PAGES_API >= KERNEL_VERSION(4, 6, 0)
+ if (R0Process == RTR0ProcHandleSelf())
+ rc = get_user_pages(R3Ptr, /* Where from. */
+ cPages, /* How many pages. */
+# if GET_USER_PAGES_API >= KERNEL_VERSION(4, 9, 0)
+ fWrite ? FOLL_WRITE | /* Write to memory. */
+ FOLL_FORCE /* force write access. */
+ : 0, /* Write to memory. */
+# else
+ fWrite, /* Write to memory. */
+ fWrite, /* force write access. */
+# endif
+ &pMemLnx->apPages[0], /* Page array. */
+ papVMAs); /* vmas */
+ /*
+ * Actually this should not happen at the moment as call this function
+ * only for our own process.
+ */
+ else
+ rc = get_user_pages_remote(
+ pTask, /* Task for fault accounting. */
+ pTask->mm, /* Whose pages. */
+ R3Ptr, /* Where from. */
+ cPages, /* How many pages. */
+# if GET_USER_PAGES_API >= KERNEL_VERSION(4, 9, 0)
+ fWrite ? FOLL_WRITE | /* Write to memory. */
+ FOLL_FORCE /* force write access. */
+ : 0, /* Write to memory. */
+# else
+ fWrite, /* Write to memory. */
+ fWrite, /* force write access. */
+# endif
+ &pMemLnx->apPages[0], /* Page array. */
+ papVMAs /* vmas */
+# if GET_USER_PAGES_API >= KERNEL_VERSION(4, 10, 0)
+ , NULL /* locked */
+# endif
+ );
+#else /* GET_USER_PAGES_API < KERNEL_VERSION(4, 6, 0) */
+ rc = get_user_pages(pTask, /* Task for fault accounting. */
+ pTask->mm, /* Whose pages. */
+ R3Ptr, /* Where from. */
+ cPages, /* How many pages. */
+# if GET_USER_PAGES_API >= KERNEL_VERSION(4, 9, 0)
+ fWrite ? FOLL_WRITE | /* Write to memory. */
+ FOLL_FORCE /* force write access. */
+ : 0, /* Write to memory. */
+# else
+ fWrite, /* Write to memory. */
+ fWrite, /* force write access. */
+# endif
+ &pMemLnx->apPages[0], /* Page array. */
+ papVMAs); /* vmas */
+#endif /* GET_USER_PAGES_API < KERNEL_VERSION(4, 6, 0) */
+ if (rc == cPages)
+ {
+ /*
+ * Flush dcache (required?), protect against fork and _really_ pin the page
+ * table entries. get_user_pages() will protect against swapping out the
+ * pages but it will NOT protect against removing page table entries. This
+ * can be achieved with
+ * - using mlock / mmap(..., MAP_LOCKED, ...) from userland. This requires
+ * an appropriate limit set up with setrlimit(..., RLIMIT_MEMLOCK, ...).
+ * Usual Linux distributions support only a limited size of locked pages
+ * (e.g. 32KB).
+ * - setting the PageReserved bit (as we do in rtR0MemObjLinuxAllocPages()
+ * or by
+ * - setting the VM_LOCKED flag. This is the same as doing mlock() without
+ * a range check.
+ */
+ /** @todo The Linux fork() protection will require more work if this API
+ * is to be used for anything but locking VM pages. */
+ while (rc-- > 0)
+ {
+ flush_dcache_page(pMemLnx->apPages[rc]);
+ papVMAs[rc]->vm_flags |= (VM_DONTCOPY | VM_LOCKED);
+ }
+
+ up_read(&pTask->mm->mmap_sem);
+
+ RTMemFree(papVMAs);
+
+ pMemLnx->Core.u.Lock.R0Process = R0Process;
+ pMemLnx->cPages = cPages;
+ Assert(!pMemLnx->fMappedToRing0);
+ *ppMem = &pMemLnx->Core;
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Failed - we need to unlock any pages that we succeeded to lock.
+ */
+ while (rc-- > 0)
+ {
+ if (!PageReserved(pMemLnx->apPages[rc]))
+ SetPageDirty(pMemLnx->apPages[rc]);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0)
+ put_page(pMemLnx->apPages[rc]);
+#else
+ page_cache_release(pMemLnx->apPages[rc]);
+#endif
+ }
+
+ up_read(&pTask->mm->mmap_sem);
+
+ RTMemFree(papVMAs);
+ rc = VERR_LOCK_FAILED;
+ }
+
+ rtR0MemObjDelete(&pMemLnx->Core);
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc;
+}
+
+
+DECLHIDDEN(int) rtR0MemObjNativeLockKernel(PPRTR0MEMOBJINTERNAL ppMem, void *pv, size_t cb, uint32_t fAccess)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+ void *pvLast = (uint8_t *)pv + cb - 1;
+ size_t const cPages = cb >> PAGE_SHIFT;
+ PRTR0MEMOBJLNX pMemLnx;
+ bool fLinearMapping;
+ int rc;
+ uint8_t *pbPage;
+ size_t iPage;
+ NOREF(fAccess);
+
+ if ( !RTR0MemKernelIsValidAddr(pv)
+ || !RTR0MemKernelIsValidAddr(pv + cb))
+ return VERR_INVALID_PARAMETER;
+
+ /*
+ * The lower part of the kernel memory has a linear mapping between
+ * physical and virtual addresses. So we take a short cut here. This is
+ * assumed to be the cleanest way to handle those addresses (and the code
+ * is well tested, though the test for determining it is not very nice).
+ * If we ever decide it isn't we can still remove it.
+ */
+#if 0
+ fLinearMapping = (unsigned long)pvLast < VMALLOC_START;
+#else
+ fLinearMapping = (unsigned long)pv >= (unsigned long)__va(0)
+ && (unsigned long)pvLast < (unsigned long)high_memory;
+#endif
+
+ /*
+ * Allocate the memory object.
+ */
+ pMemLnx = (PRTR0MEMOBJLNX)rtR0MemObjNew(RT_OFFSETOF(RTR0MEMOBJLNX, apPages[cPages]), RTR0MEMOBJTYPE_LOCK, pv, cb);
+ if (!pMemLnx)
+ {
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VERR_NO_MEMORY;
+ }
+
+ /*
+ * Gather the pages.
+ * We ASSUME all kernel pages are non-swappable and non-movable.
+ */
+ rc = VINF_SUCCESS;
+ pbPage = (uint8_t *)pvLast;
+ iPage = cPages;
+ if (!fLinearMapping)
+ {
+ while (iPage-- > 0)
+ {
+ struct page *pPage = rtR0MemObjLinuxVirtToPage(pbPage);
+ if (RT_UNLIKELY(!pPage))
+ {
+ rc = VERR_LOCK_FAILED;
+ break;
+ }
+ pMemLnx->apPages[iPage] = pPage;
+ pbPage -= PAGE_SIZE;
+ }
+ }
+ else
+ {
+ while (iPage-- > 0)
+ {
+ pMemLnx->apPages[iPage] = virt_to_page(pbPage);
+ pbPage -= PAGE_SIZE;
+ }
+ }
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Complete the memory object and return.
+ */
+ pMemLnx->Core.u.Lock.R0Process = NIL_RTR0PROCESS;
+ pMemLnx->cPages = cPages;
+ Assert(!pMemLnx->fMappedToRing0);
+ *ppMem = &pMemLnx->Core;
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+ }
+
+ rtR0MemObjDelete(&pMemLnx->Core);
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc;
+}
+
+
+DECLHIDDEN(int) rtR0MemObjNativeReserveKernel(PPRTR0MEMOBJINTERNAL ppMem, void *pvFixed, size_t cb, size_t uAlignment)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 22)
+ IPRT_LINUX_SAVE_EFL_AC();
+ const size_t cPages = cb >> PAGE_SHIFT;
+ struct page *pDummyPage;
+ struct page **papPages;
+
+ /* check for unsupported stuff. */
+ AssertMsgReturn(pvFixed == (void *)-1, ("%p\n", pvFixed), VERR_NOT_SUPPORTED);
+ if (uAlignment > PAGE_SIZE)
+ return VERR_NOT_SUPPORTED;
+
+ /*
+ * Allocate a dummy page and create a page pointer array for vmap such that
+ * the dummy page is mapped all over the reserved area.
+ */
+ pDummyPage = alloc_page(GFP_HIGHUSER | __GFP_NOWARN);
+ if (pDummyPage)
+ {
+ papPages = RTMemAlloc(sizeof(*papPages) * cPages);
+ if (papPages)
+ {
+ void *pv;
+ size_t iPage = cPages;
+ while (iPage-- > 0)
+ papPages[iPage] = pDummyPage;
+# ifdef VM_MAP
+ pv = vmap(papPages, cPages, VM_MAP, PAGE_KERNEL_RO);
+# else
+ pv = vmap(papPages, cPages, VM_ALLOC, PAGE_KERNEL_RO);
+# endif
+ RTMemFree(papPages);
+ if (pv)
+ {
+ PRTR0MEMOBJLNX pMemLnx = (PRTR0MEMOBJLNX)rtR0MemObjNew(sizeof(*pMemLnx), RTR0MEMOBJTYPE_RES_VIRT, pv, cb);
+ if (pMemLnx)
+ {
+ pMemLnx->Core.u.ResVirt.R0Process = NIL_RTR0PROCESS;
+ pMemLnx->cPages = 1;
+ pMemLnx->apPages[0] = pDummyPage;
+ *ppMem = &pMemLnx->Core;
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+ }
+ vunmap(pv);
+ }
+ }
+ __free_page(pDummyPage);
+ }
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VERR_NO_MEMORY;
+
+#else /* < 2.4.22 */
+ /*
+ * Could probably use ioremap here, but the caller is in a better position than us
+ * to select some safe physical memory.
+ */
+ return VERR_NOT_SUPPORTED;
+#endif
+}
+
+
+DECLHIDDEN(int) rtR0MemObjNativeReserveUser(PPRTR0MEMOBJINTERNAL ppMem, RTR3PTR R3PtrFixed, size_t cb, size_t uAlignment, RTR0PROCESS R0Process)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+ PRTR0MEMOBJLNX pMemLnx;
+ void *pv;
+ struct task_struct *pTask = rtR0ProcessToLinuxTask(R0Process);
+ if (!pTask)
+ return VERR_NOT_SUPPORTED;
+
+ /*
+ * Check that the specified alignment is supported.
+ */
+ if (uAlignment > PAGE_SIZE)
+ return VERR_NOT_SUPPORTED;
+
+ /*
+ * Let rtR0MemObjLinuxDoMmap do the difficult bits.
+ */
+ pv = rtR0MemObjLinuxDoMmap(R3PtrFixed, cb, uAlignment, pTask, RTMEM_PROT_NONE);
+ if (pv == (void *)-1)
+ {
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VERR_NO_MEMORY;
+ }
+
+ pMemLnx = (PRTR0MEMOBJLNX)rtR0MemObjNew(sizeof(*pMemLnx), RTR0MEMOBJTYPE_RES_VIRT, pv, cb);
+ if (!pMemLnx)
+ {
+ rtR0MemObjLinuxDoMunmap(pv, cb, pTask);
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VERR_NO_MEMORY;
+ }
+
+ pMemLnx->Core.u.ResVirt.R0Process = R0Process;
+ *ppMem = &pMemLnx->Core;
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+}
+
+
+DECLHIDDEN(int) rtR0MemObjNativeMapKernel(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ pMemToMap,
+ void *pvFixed, size_t uAlignment,
+ unsigned fProt, size_t offSub, size_t cbSub)
+{
+ int rc = VERR_NO_MEMORY;
+ PRTR0MEMOBJLNX pMemLnxToMap = (PRTR0MEMOBJLNX)pMemToMap;
+ PRTR0MEMOBJLNX pMemLnx;
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ /* Fail if requested to do something we can't. */
+ AssertMsgReturn(!offSub && !cbSub, ("%#x %#x\n", offSub, cbSub), VERR_NOT_SUPPORTED);
+ AssertMsgReturn(pvFixed == (void *)-1, ("%p\n", pvFixed), VERR_NOT_SUPPORTED);
+ if (uAlignment > PAGE_SIZE)
+ return VERR_NOT_SUPPORTED;
+
+ /*
+ * Create the IPRT memory object.
+ */
+ pMemLnx = (PRTR0MEMOBJLNX)rtR0MemObjNew(sizeof(*pMemLnx), RTR0MEMOBJTYPE_MAPPING, NULL, pMemLnxToMap->Core.cb);
+ if (pMemLnx)
+ {
+ if (pMemLnxToMap->cPages)
+ {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 22)
+ /*
+ * Use vmap - 2.4.22 and later.
+ */
+ pgprot_t fPg = rtR0MemObjLinuxConvertProt(fProt, true /* kernel */);
+# ifdef VM_MAP
+ pMemLnx->Core.pv = vmap(&pMemLnxToMap->apPages[0], pMemLnxToMap->cPages, VM_MAP, fPg);
+# else
+ pMemLnx->Core.pv = vmap(&pMemLnxToMap->apPages[0], pMemLnxToMap->cPages, VM_ALLOC, fPg);
+# endif
+ if (pMemLnx->Core.pv)
+ {
+ pMemLnx->fMappedToRing0 = true;
+ rc = VINF_SUCCESS;
+ }
+ else
+ rc = VERR_MAP_FAILED;
+
+#else /* < 2.4.22 */
+ /*
+ * Only option here is to share mappings if possible and forget about fProt.
+ */
+ if (rtR0MemObjIsRing3(pMemToMap))
+ rc = VERR_NOT_SUPPORTED;
+ else
+ {
+ rc = VINF_SUCCESS;
+ if (!pMemLnxToMap->Core.pv)
+ rc = rtR0MemObjLinuxVMap(pMemLnxToMap, !!(fProt & RTMEM_PROT_EXEC));
+ if (RT_SUCCESS(rc))
+ {
+ Assert(pMemLnxToMap->Core.pv);
+ pMemLnx->Core.pv = pMemLnxToMap->Core.pv;
+ }
+ }
+#endif
+ }
+ else
+ {
+ /*
+ * MMIO / physical memory.
+ */
+ Assert(pMemLnxToMap->Core.enmType == RTR0MEMOBJTYPE_PHYS && !pMemLnxToMap->Core.u.Phys.fAllocated);
+ pMemLnx->Core.pv = pMemLnxToMap->Core.u.Phys.uCachePolicy == RTMEM_CACHE_POLICY_MMIO
+ ? ioremap_nocache(pMemLnxToMap->Core.u.Phys.PhysBase, pMemLnxToMap->Core.cb)
+ : ioremap(pMemLnxToMap->Core.u.Phys.PhysBase, pMemLnxToMap->Core.cb);
+ if (pMemLnx->Core.pv)
+ {
+ /** @todo fix protection. */
+ rc = VINF_SUCCESS;
+ }
+ }
+ if (RT_SUCCESS(rc))
+ {
+ pMemLnx->Core.u.Mapping.R0Process = NIL_RTR0PROCESS;
+ *ppMem = &pMemLnx->Core;
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+ }
+ rtR0MemObjDelete(&pMemLnx->Core);
+ }
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc;
+}
+
+
+#ifdef VBOX_USE_PAE_HACK
+/**
+ * Replace the PFN of a PTE with the address of the actual page.
+ *
+ * The caller maps a reserved dummy page at the address with the desired access
+ * and flags.
+ *
+ * This hack is required for older Linux kernels which don't provide
+ * remap_pfn_range().
+ *
+ * @returns 0 on success, -ENOMEM on failure.
+ * @param mm The memory context.
+ * @param ulAddr The mapping address.
+ * @param Phys The physical address of the page to map.
+ */
+static int rtR0MemObjLinuxFixPte(struct mm_struct *mm, unsigned long ulAddr, RTHCPHYS Phys)
+{
+ int rc = -ENOMEM;
+ pgd_t *pgd;
+
+ spin_lock(&mm->page_table_lock);
+
+ pgd = pgd_offset(mm, ulAddr);
+ if (!pgd_none(*pgd) && !pgd_bad(*pgd))
+ {
+ pmd_t *pmd = pmd_offset(pgd, ulAddr);
+ if (!pmd_none(*pmd))
+ {
+ pte_t *ptep = pte_offset_map(pmd, ulAddr);
+ if (ptep)
+ {
+ pte_t pte = *ptep;
+ pte.pte_high &= 0xfff00000;
+ pte.pte_high |= ((Phys >> 32) & 0x000fffff);
+ pte.pte_low &= 0x00000fff;
+ pte.pte_low |= (Phys & 0xfffff000);
+ set_pte(ptep, pte);
+ pte_unmap(ptep);
+ rc = 0;
+ }
+ }
+ }
+
+ spin_unlock(&mm->page_table_lock);
+ return rc;
+}
+#endif /* VBOX_USE_PAE_HACK */
+
+
+DECLHIDDEN(int) rtR0MemObjNativeMapUser(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ pMemToMap, RTR3PTR R3PtrFixed,
+ size_t uAlignment, unsigned fProt, RTR0PROCESS R0Process)
+{
+ struct task_struct *pTask = rtR0ProcessToLinuxTask(R0Process);
+ PRTR0MEMOBJLNX pMemLnxToMap = (PRTR0MEMOBJLNX)pMemToMap;
+ int rc = VERR_NO_MEMORY;
+ PRTR0MEMOBJLNX pMemLnx;
+#ifdef VBOX_USE_PAE_HACK
+ struct page *pDummyPage;
+ RTHCPHYS DummyPhys;
+#endif
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ /*
+ * Check for restrictions.
+ */
+ if (!pTask)
+ return VERR_NOT_SUPPORTED;
+ if (uAlignment > PAGE_SIZE)
+ return VERR_NOT_SUPPORTED;
+
+#ifdef VBOX_USE_PAE_HACK
+ /*
+ * Allocate a dummy page for use when mapping the memory.
+ */
+ pDummyPage = alloc_page(GFP_USER | __GFP_NOWARN);
+ if (!pDummyPage)
+ {
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VERR_NO_MEMORY;
+ }
+ SetPageReserved(pDummyPage);
+ DummyPhys = page_to_phys(pDummyPage);
+#endif
+
+ /*
+ * Create the IPRT memory object.
+ */
+ pMemLnx = (PRTR0MEMOBJLNX)rtR0MemObjNew(sizeof(*pMemLnx), RTR0MEMOBJTYPE_MAPPING, NULL, pMemLnxToMap->Core.cb);
+ if (pMemLnx)
+ {
+ /*
+ * Allocate user space mapping.
+ */
+ void *pv;
+ pv = rtR0MemObjLinuxDoMmap(R3PtrFixed, pMemLnxToMap->Core.cb, uAlignment, pTask, fProt);
+ if (pv != (void *)-1)
+ {
+ /*
+ * Map page by page into the mmap area.
+ * This is generic, paranoid and not very efficient.
+ */
+ pgprot_t fPg = rtR0MemObjLinuxConvertProt(fProt, false /* user */);
+ unsigned long ulAddrCur = (unsigned long)pv;
+ const size_t cPages = pMemLnxToMap->Core.cb >> PAGE_SHIFT;
+ size_t iPage;
+
+ down_write(&pTask->mm->mmap_sem);
+
+ rc = VINF_SUCCESS;
+ if (pMemLnxToMap->cPages)
+ {
+ for (iPage = 0; iPage < cPages; iPage++, ulAddrCur += PAGE_SIZE)
+ {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11)
+ RTHCPHYS Phys = page_to_phys(pMemLnxToMap->apPages[iPage]);
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) || defined(HAVE_26_STYLE_REMAP_PAGE_RANGE)
+ struct vm_area_struct *vma = find_vma(pTask->mm, ulAddrCur); /* this is probably the same for all the pages... */
+ AssertBreakStmt(vma, rc = VERR_INTERNAL_ERROR);
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) && defined(RT_ARCH_X86)
+ /* remap_page_range() limitation on x86 */
+ AssertBreakStmt(Phys < _4G, rc = VERR_NO_MEMORY);
+#endif
+
+#if defined(VBOX_USE_INSERT_PAGE) && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
+ rc = vm_insert_page(vma, ulAddrCur, pMemLnxToMap->apPages[iPage]);
+ /* Thes flags help making 100% sure some bad stuff wont happen (swap, core, ++).
+ * See remap_pfn_range() in mm/memory.c */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)
+ vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+#else
+ vma->vm_flags |= VM_RESERVED;
+#endif
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
+ rc = remap_pfn_range(vma, ulAddrCur, page_to_pfn(pMemLnxToMap->apPages[iPage]), PAGE_SIZE, fPg);
+#elif defined(VBOX_USE_PAE_HACK)
+ rc = remap_page_range(vma, ulAddrCur, DummyPhys, PAGE_SIZE, fPg);
+ if (!rc)
+ rc = rtR0MemObjLinuxFixPte(pTask->mm, ulAddrCur, Phys);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) || defined(HAVE_26_STYLE_REMAP_PAGE_RANGE)
+ rc = remap_page_range(vma, ulAddrCur, Phys, PAGE_SIZE, fPg);
+#else /* 2.4 */
+ rc = remap_page_range(ulAddrCur, Phys, PAGE_SIZE, fPg);
+#endif
+ if (rc)
+ {
+ rc = VERR_NO_MEMORY;
+ break;
+ }
+ }
+ }
+ else
+ {
+ RTHCPHYS Phys;
+ if (pMemLnxToMap->Core.enmType == RTR0MEMOBJTYPE_PHYS)
+ Phys = pMemLnxToMap->Core.u.Phys.PhysBase;
+ else if (pMemLnxToMap->Core.enmType == RTR0MEMOBJTYPE_CONT)
+ Phys = pMemLnxToMap->Core.u.Cont.Phys;
+ else
+ {
+ AssertMsgFailed(("%d\n", pMemLnxToMap->Core.enmType));
+ Phys = NIL_RTHCPHYS;
+ }
+ if (Phys != NIL_RTHCPHYS)
+ {
+ for (iPage = 0; iPage < cPages; iPage++, ulAddrCur += PAGE_SIZE, Phys += PAGE_SIZE)
+ {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) || defined(HAVE_26_STYLE_REMAP_PAGE_RANGE)
+ struct vm_area_struct *vma = find_vma(pTask->mm, ulAddrCur); /* this is probably the same for all the pages... */
+ AssertBreakStmt(vma, rc = VERR_INTERNAL_ERROR);
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) && defined(RT_ARCH_X86)
+ /* remap_page_range() limitation on x86 */
+ AssertBreakStmt(Phys < _4G, rc = VERR_NO_MEMORY);
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
+ rc = remap_pfn_range(vma, ulAddrCur, Phys, PAGE_SIZE, fPg);
+#elif defined(VBOX_USE_PAE_HACK)
+ rc = remap_page_range(vma, ulAddrCur, DummyPhys, PAGE_SIZE, fPg);
+ if (!rc)
+ rc = rtR0MemObjLinuxFixPte(pTask->mm, ulAddrCur, Phys);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) || defined(HAVE_26_STYLE_REMAP_PAGE_RANGE)
+ rc = remap_page_range(vma, ulAddrCur, Phys, PAGE_SIZE, fPg);
+#else /* 2.4 */
+ rc = remap_page_range(ulAddrCur, Phys, PAGE_SIZE, fPg);
+#endif
+ if (rc)
+ {
+ rc = VERR_NO_MEMORY;
+ break;
+ }
+ }
+ }
+ }
+
+#ifdef CONFIG_NUMA_BALANCING
+# if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
+# ifdef RHEL_RELEASE_CODE
+# if RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7, 0)
+# define VBOX_NUMA_HACK_OLD
+# endif
+# endif
+# endif
+ if (RT_SUCCESS(rc))
+ {
+ /** @todo Ugly hack! But right now we have no other means to
+ * disable automatic NUMA page balancing. */
+# ifdef RT_OS_X86
+# ifdef VBOX_NUMA_HACK_OLD
+ pTask->mm->numa_next_reset = jiffies + 0x7fffffffUL;
+# endif
+ pTask->mm->numa_next_scan = jiffies + 0x7fffffffUL;
+# else
+# ifdef VBOX_NUMA_HACK_OLD
+ pTask->mm->numa_next_reset = jiffies + 0x7fffffffffffffffUL;
+# endif
+ pTask->mm->numa_next_scan = jiffies + 0x7fffffffffffffffUL;
+# endif
+ }
+#endif /* CONFIG_NUMA_BALANCING */
+
+ up_write(&pTask->mm->mmap_sem);
+
+ if (RT_SUCCESS(rc))
+ {
+#ifdef VBOX_USE_PAE_HACK
+ __free_page(pDummyPage);
+#endif
+ pMemLnx->Core.pv = pv;
+ pMemLnx->Core.u.Mapping.R0Process = R0Process;
+ *ppMem = &pMemLnx->Core;
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Bail out.
+ */
+ rtR0MemObjLinuxDoMunmap(pv, pMemLnxToMap->Core.cb, pTask);
+ }
+ rtR0MemObjDelete(&pMemLnx->Core);
+ }
+#ifdef VBOX_USE_PAE_HACK
+ __free_page(pDummyPage);
+#endif
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc;
+}
+
+
+DECLHIDDEN(int) rtR0MemObjNativeProtect(PRTR0MEMOBJINTERNAL pMem, size_t offSub, size_t cbSub, uint32_t fProt)
+{
+ NOREF(pMem);
+ NOREF(offSub);
+ NOREF(cbSub);
+ NOREF(fProt);
+ return VERR_NOT_SUPPORTED;
+}
+
+
+DECLHIDDEN(RTHCPHYS) rtR0MemObjNativeGetPagePhysAddr(PRTR0MEMOBJINTERNAL pMem, size_t iPage)
+{
+ PRTR0MEMOBJLNX pMemLnx = (PRTR0MEMOBJLNX)pMem;
+
+ if (pMemLnx->cPages)
+ return page_to_phys(pMemLnx->apPages[iPage]);
+
+ switch (pMemLnx->Core.enmType)
+ {
+ case RTR0MEMOBJTYPE_CONT:
+ return pMemLnx->Core.u.Cont.Phys + (iPage << PAGE_SHIFT);
+
+ case RTR0MEMOBJTYPE_PHYS:
+ return pMemLnx->Core.u.Phys.PhysBase + (iPage << PAGE_SHIFT);
+
+ /* the parent knows */
+ case RTR0MEMOBJTYPE_MAPPING:
+ return rtR0MemObjNativeGetPagePhysAddr(pMemLnx->Core.uRel.Child.pParent, iPage);
+
+ /* cPages > 0 */
+ case RTR0MEMOBJTYPE_LOW:
+ case RTR0MEMOBJTYPE_LOCK:
+ case RTR0MEMOBJTYPE_PHYS_NC:
+ case RTR0MEMOBJTYPE_PAGE:
+ default:
+ AssertMsgFailed(("%d\n", pMemLnx->Core.enmType));
+ /* fall thru */
+
+ case RTR0MEMOBJTYPE_RES_VIRT:
+ return NIL_RTHCPHYS;
+ }
+}
+
--- /dev/null
+/* $Id: memuserkernel-r0drv-linux.c $ */
+/** @file
+ * IPRT - User & Kernel Memory, Ring-0 Driver, Linux.
+ */
+
+/*
+ * Copyright (C) 2009-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "the-linux-kernel.h"
+#include "internal/iprt.h"
+
+#include <iprt/mem.h>
+#include <iprt/err.h>
+
+
+RTR0DECL(int) RTR0MemUserCopyFrom(void *pvDst, RTR3PTR R3PtrSrc, size_t cb)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+ if (RT_LIKELY(copy_from_user(pvDst, (void *)R3PtrSrc, cb) == 0))
+ {
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+ }
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VERR_ACCESS_DENIED;
+}
+RT_EXPORT_SYMBOL(RTR0MemUserCopyFrom);
+
+
+RTR0DECL(int) RTR0MemUserCopyTo(RTR3PTR R3PtrDst, void const *pvSrc, size_t cb)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+ if (RT_LIKELY(copy_to_user((void *)R3PtrDst, pvSrc, cb) == 0))
+ {
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+ }
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VERR_ACCESS_DENIED;
+}
+RT_EXPORT_SYMBOL(RTR0MemUserCopyTo);
+
+
+RTR0DECL(bool) RTR0MemUserIsValidAddr(RTR3PTR R3Ptr)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+ bool fRc = access_ok(VERIFY_READ, (void *)R3Ptr, 1);
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return fRc;
+}
+RT_EXPORT_SYMBOL(RTR0MemUserIsValidAddr);
+
+
+RTR0DECL(bool) RTR0MemKernelIsValidAddr(void *pv)
+{
+ /* Couldn't find a straight forward way of doing this... */
+#if defined(RT_ARCH_X86) && defined(CONFIG_X86_HIGH_ENTRY)
+ return true; /* ?? */
+#elif defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)
+ return (uintptr_t)pv >= PAGE_OFFSET;
+#else
+# error "PORT ME"
+ return !access_ok(VERIFY_READ, pv, 1);
+#endif
+}
+RT_EXPORT_SYMBOL(RTR0MemKernelIsValidAddr);
+
+
+RTR0DECL(bool) RTR0MemAreKrnlAndUsrDifferent(void)
+{
+#if defined(RT_ARCH_X86) && defined(CONFIG_X86_HIGH_ENTRY) /* ?? */
+ return false;
+#else
+ return true;
+#endif
+}
+RT_EXPORT_SYMBOL(RTR0MemAreKrnlAndUsrDifferent);
+
+
+/**
+ * Treats both source and destination as unsafe buffers.
+ */
+static int rtR0MemKernelCopyLnxWorker(void *pvDst, void const *pvSrc, size_t cb)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 55)
+/* _ASM_EXTABLE was introduced in 2.6.25 from what I can tell. Using #ifndef
+ here since it has to be a macro and you never know what someone might have
+ backported to an earlier kernel release. */
+# ifndef _ASM_EXTABLE
+# if ARCH_BITS == 32
+# define _ASM_EXTABLE(a_Instr, a_Resume) \
+ ".section __ex_table,\"a\"\n" \
+ ".balign 4\n" \
+ ".long " #a_Instr "\n" \
+ ".long " #a_Resume "\n" \
+ ".previous\n"
+# else
+# define _ASM_EXTABLE(a_Instr, a_Resume) \
+ ".section __ex_table,\"a\"\n" \
+ ".balign 8\n" \
+ ".quad " #a_Instr "\n" \
+ ".quad " #a_Resume "\n" \
+ ".previous\n"
+# endif
+# endif /* !_ASM_EXTABLE */
+ int rc;
+ IPRT_LINUX_SAVE_EFL_AC(); /* paranoia */
+ if (!cb)
+ return VINF_SUCCESS;
+
+ __asm__ __volatile__ ("cld\n"
+ "1:\n\t"
+ "rep; movsb\n"
+ "2:\n\t"
+ ".section .fixup,\"ax\"\n"
+ "3:\n\t"
+ "movl %4, %0\n"
+ ".previous\n"
+ _ASM_EXTABLE(1b, 3b)
+ : "=r" (rc),
+ "=D" (pvDst),
+ "=S" (pvSrc),
+ "=c" (cb)
+ : "i" (VERR_ACCESS_DENIED),
+ "0" (VINF_SUCCESS),
+ "1" (pvDst),
+ "2" (pvSrc),
+ "3" (cb)
+ : "memory");
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc;
+#else
+ return VERR_NOT_SUPPORTED;
+#endif
+}
+
+
+RTR0DECL(int) RTR0MemKernelCopyFrom(void *pvDst, void const *pvSrc, size_t cb)
+{
+ return rtR0MemKernelCopyLnxWorker(pvDst, pvSrc, cb);
+}
+RT_EXPORT_SYMBOL(RTR0MemKernelCopyFrom);
+
+
+RTR0DECL(int) RTR0MemKernelCopyTo(void *pvDst, void const *pvSrc, size_t cb)
+{
+ return rtR0MemKernelCopyLnxWorker(pvDst, pvSrc, cb);
+}
+RT_EXPORT_SYMBOL(RTR0MemKernelCopyTo);
+
--- /dev/null
+/* $Id: mp-r0drv-linux.c $ */
+/** @file
+ * IPRT - Multiprocessor, Ring-0 Driver, Linux.
+ */
+
+/*
+ * Copyright (C) 2008-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "the-linux-kernel.h"
+#include "internal/iprt.h"
+
+#include <iprt/mp.h>
+#include <iprt/cpuset.h>
+#include <iprt/err.h>
+#include <iprt/asm.h>
+#include <iprt/thread.h>
+#include "r0drv/mp-r0drv.h"
+
+#ifdef nr_cpumask_bits
+# define VBOX_NR_CPUMASK_BITS nr_cpumask_bits
+#else
+# define VBOX_NR_CPUMASK_BITS NR_CPUS
+#endif
+
+RTDECL(RTCPUID) RTMpCpuId(void)
+{
+ return smp_processor_id();
+}
+RT_EXPORT_SYMBOL(RTMpCpuId);
+
+
+RTDECL(int) RTMpCurSetIndex(void)
+{
+ return smp_processor_id();
+}
+RT_EXPORT_SYMBOL(RTMpCurSetIndex);
+
+
+RTDECL(int) RTMpCurSetIndexAndId(PRTCPUID pidCpu)
+{
+ return *pidCpu = smp_processor_id();
+}
+RT_EXPORT_SYMBOL(RTMpCurSetIndexAndId);
+
+
+RTDECL(int) RTMpCpuIdToSetIndex(RTCPUID idCpu)
+{
+ return idCpu < RTCPUSET_MAX_CPUS && idCpu < VBOX_NR_CPUMASK_BITS ? (int)idCpu : -1;
+}
+RT_EXPORT_SYMBOL(RTMpCpuIdToSetIndex);
+
+
+RTDECL(RTCPUID) RTMpCpuIdFromSetIndex(int iCpu)
+{
+ return iCpu < VBOX_NR_CPUMASK_BITS ? (RTCPUID)iCpu : NIL_RTCPUID;
+}
+RT_EXPORT_SYMBOL(RTMpCpuIdFromSetIndex);
+
+
+RTDECL(RTCPUID) RTMpGetMaxCpuId(void)
+{
+ return VBOX_NR_CPUMASK_BITS - 1; //???
+}
+RT_EXPORT_SYMBOL(RTMpGetMaxCpuId);
+
+
+RTDECL(bool) RTMpIsCpuPossible(RTCPUID idCpu)
+{
+#if defined(CONFIG_SMP)
+ if (RT_UNLIKELY(idCpu >= VBOX_NR_CPUMASK_BITS))
+ return false;
+
+# if defined(cpu_possible)
+ return cpu_possible(idCpu);
+# else /* < 2.5.29 */
+ return idCpu < (RTCPUID)smp_num_cpus;
+# endif
+#else
+ return idCpu == RTMpCpuId();
+#endif
+}
+RT_EXPORT_SYMBOL(RTMpIsCpuPossible);
+
+
+RTDECL(PRTCPUSET) RTMpGetSet(PRTCPUSET pSet)
+{
+ RTCPUID idCpu;
+
+ RTCpuSetEmpty(pSet);
+ idCpu = RTMpGetMaxCpuId();
+ do
+ {
+ if (RTMpIsCpuPossible(idCpu))
+ RTCpuSetAdd(pSet, idCpu);
+ } while (idCpu-- > 0);
+ return pSet;
+}
+RT_EXPORT_SYMBOL(RTMpGetSet);
+
+
+RTDECL(RTCPUID) RTMpGetCount(void)
+{
+#ifdef CONFIG_SMP
+# if defined(CONFIG_HOTPLUG_CPU) /* introduced & uses cpu_present */
+ return num_present_cpus();
+# elif defined(num_possible_cpus)
+ return num_possible_cpus();
+# elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
+ return smp_num_cpus;
+# else
+ RTCPUSET Set;
+ RTMpGetSet(&Set);
+ return RTCpuSetCount(&Set);
+# endif
+#else
+ return 1;
+#endif
+}
+RT_EXPORT_SYMBOL(RTMpGetCount);
+
+
+RTDECL(bool) RTMpIsCpuOnline(RTCPUID idCpu)
+{
+#ifdef CONFIG_SMP
+ if (RT_UNLIKELY(idCpu >= VBOX_NR_CPUMASK_BITS))
+ return false;
+# ifdef cpu_online
+ return cpu_online(idCpu);
+# else /* 2.4: */
+ return cpu_online_map & RT_BIT_64(idCpu);
+# endif
+#else
+ return idCpu == RTMpCpuId();
+#endif
+}
+RT_EXPORT_SYMBOL(RTMpIsCpuOnline);
+
+
+RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet)
+{
+#ifdef CONFIG_SMP
+ RTCPUID idCpu;
+
+ RTCpuSetEmpty(pSet);
+ idCpu = RTMpGetMaxCpuId();
+ do
+ {
+ if (RTMpIsCpuOnline(idCpu))
+ RTCpuSetAdd(pSet, idCpu);
+ } while (idCpu-- > 0);
+#else
+ RTCpuSetEmpty(pSet);
+ RTCpuSetAdd(pSet, RTMpCpuId());
+#endif
+ return pSet;
+}
+RT_EXPORT_SYMBOL(RTMpGetOnlineSet);
+
+
+RTDECL(RTCPUID) RTMpGetOnlineCount(void)
+{
+#ifdef CONFIG_SMP
+# if defined(num_online_cpus)
+ return num_online_cpus();
+# else
+ RTCPUSET Set;
+ RTMpGetOnlineSet(&Set);
+ return RTCpuSetCount(&Set);
+# endif
+#else
+ return 1;
+#endif
+}
+RT_EXPORT_SYMBOL(RTMpGetOnlineCount);
+
+
+RTDECL(bool) RTMpIsCpuWorkPending(void)
+{
+ /** @todo (not used on non-Windows platforms yet). */
+ return false;
+}
+RT_EXPORT_SYMBOL(RTMpIsCpuWorkPending);
+
+
+/**
+ * Wrapper between the native linux per-cpu callbacks and PFNRTWORKER.
+ *
+ * @param pvInfo Pointer to the RTMPARGS package.
+ */
+static void rtmpLinuxWrapper(void *pvInfo)
+{
+ PRTMPARGS pArgs = (PRTMPARGS)pvInfo;
+ ASMAtomicIncU32(&pArgs->cHits);
+ pArgs->pfnWorker(RTMpCpuId(), pArgs->pvUser1, pArgs->pvUser2);
+}
+
+
+/**
+ * Wrapper between the native linux per-cpu callbacks and PFNRTWORKER, does hit
+ * increment after calling the worker.
+ *
+ * @param pvInfo Pointer to the RTMPARGS package.
+ */
+static void rtmpLinuxWrapperPostInc(void *pvInfo)
+{
+ PRTMPARGS pArgs = (PRTMPARGS)pvInfo;
+ pArgs->pfnWorker(RTMpCpuId(), pArgs->pvUser1, pArgs->pvUser2);
+ ASMAtomicIncU32(&pArgs->cHits);
+}
+
+
+/**
+ * Wrapper between the native linux all-cpu callbacks and PFNRTWORKER.
+ *
+ * @param pvInfo Pointer to the RTMPARGS package.
+ */
+static void rtmpLinuxAllWrapper(void *pvInfo)
+{
+ PRTMPARGS pArgs = (PRTMPARGS)pvInfo;
+ PRTCPUSET pWorkerSet = pArgs->pWorkerSet;
+ RTCPUID idCpu = RTMpCpuId();
+ Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
+
+ if (RTCpuSetIsMember(pWorkerSet, idCpu))
+ {
+ pArgs->pfnWorker(idCpu, pArgs->pvUser1, pArgs->pvUser2);
+ RTCpuSetDel(pWorkerSet, idCpu);
+ }
+}
+
+
+RTDECL(int) RTMpOnAll(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+ int rc;
+ RTMPARGS Args;
+ RTCPUSET OnlineSet;
+ RTCPUID idCpu;
+ uint32_t cLoops;
+
+ RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
+
+ Args.pfnWorker = pfnWorker;
+ Args.pvUser1 = pvUser1;
+ Args.pvUser2 = pvUser2;
+ Args.idCpu = NIL_RTCPUID;
+ Args.cHits = 0;
+
+ RTThreadPreemptDisable(&PreemptState);
+ RTMpGetOnlineSet(&OnlineSet);
+ Args.pWorkerSet = &OnlineSet;
+ idCpu = RTMpCpuId();
+
+ if (RTCpuSetCount(&OnlineSet) > 1)
+ {
+ /* Fire the function on all other CPUs without waiting for completion. */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+ rc = smp_call_function(rtmpLinuxAllWrapper, &Args, 0 /* wait */);
+#else
+ rc = smp_call_function(rtmpLinuxAllWrapper, &Args, 0 /* retry */, 0 /* wait */);
+#endif
+ Assert(!rc); NOREF(rc);
+ }
+
+ /* Fire the function on this CPU. */
+ Args.pfnWorker(idCpu, Args.pvUser1, Args.pvUser2);
+ RTCpuSetDel(Args.pWorkerSet, idCpu);
+
+ /* Wait for all of them finish. */
+ cLoops = 64000;
+ while (!RTCpuSetIsEmpty(Args.pWorkerSet))
+ {
+ /* Periodically check if any CPU in the wait set has gone offline, if so update the wait set. */
+ if (!cLoops--)
+ {
+ RTCPUSET OnlineSetNow;
+ RTMpGetOnlineSet(&OnlineSetNow);
+ RTCpuSetAnd(Args.pWorkerSet, &OnlineSetNow);
+
+ cLoops = 64000;
+ }
+
+ ASMNopPause();
+ }
+
+ RTThreadPreemptRestore(&PreemptState);
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTMpOnAll);
+
+
+RTDECL(int) RTMpOnOthers(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+ int rc;
+ RTMPARGS Args;
+
+ RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
+ Args.pfnWorker = pfnWorker;
+ Args.pvUser1 = pvUser1;
+ Args.pvUser2 = pvUser2;
+ Args.idCpu = NIL_RTCPUID;
+ Args.cHits = 0;
+
+ RTThreadPreemptDisable(&PreemptState);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+ rc = smp_call_function(rtmpLinuxWrapper, &Args, 1 /* wait */);
+#else /* older kernels */
+ rc = smp_call_function(rtmpLinuxWrapper, &Args, 0 /* retry */, 1 /* wait */);
+#endif /* older kernels */
+ RTThreadPreemptRestore(&PreemptState);
+
+ Assert(rc == 0); NOREF(rc);
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTMpOnOthers);
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
+/**
+ * Wrapper between the native linux per-cpu callbacks and PFNRTWORKER
+ * employed by RTMpOnPair on older kernels that lacks smp_call_function_many.
+ *
+ * @param pvInfo Pointer to the RTMPARGS package.
+ */
+static void rtMpLinuxOnPairWrapper(void *pvInfo)
+{
+ PRTMPARGS pArgs = (PRTMPARGS)pvInfo;
+ RTCPUID idCpu = RTMpCpuId();
+
+ if ( idCpu == pArgs->idCpu
+ || idCpu == pArgs->idCpu2)
+ {
+ pArgs->pfnWorker(idCpu, pArgs->pvUser1, pArgs->pvUser2);
+ ASMAtomicIncU32(&pArgs->cHits);
+ }
+}
+#endif
+
+
+RTDECL(int) RTMpOnPair(RTCPUID idCpu1, RTCPUID idCpu2, uint32_t fFlags, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+ int rc;
+ RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
+
+ AssertReturn(idCpu1 != idCpu2, VERR_INVALID_PARAMETER);
+ AssertReturn(!(fFlags & RTMPON_F_VALID_MASK), VERR_INVALID_FLAGS);
+
+ /*
+ * Check that both CPUs are online before doing the broadcast call.
+ */
+ RTThreadPreemptDisable(&PreemptState);
+ if ( RTMpIsCpuOnline(idCpu1)
+ && RTMpIsCpuOnline(idCpu2))
+ {
+ /*
+ * Use the smp_call_function variant taking a cpu mask where available,
+ * falling back on broadcast with filter. Slight snag if one of the
+ * CPUs is the one we're running on, we must do the call and the post
+ * call wait ourselves.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
+ /* 2.6.28 introduces CONFIG_CPUMASK_OFFSTACK */
+ cpumask_var_t DstCpuMask;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+ cpumask_t DstCpuMask;
+#endif
+ RTCPUID idCpuSelf = RTMpCpuId();
+ bool const fCallSelf = idCpuSelf == idCpu1 || idCpuSelf == idCpu2;
+ RTMPARGS Args;
+ Args.pfnWorker = pfnWorker;
+ Args.pvUser1 = pvUser1;
+ Args.pvUser2 = pvUser2;
+ Args.idCpu = idCpu1;
+ Args.idCpu2 = idCpu2;
+ Args.cHits = 0;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
+ if (!zalloc_cpumask_var(&DstCpuMask, GFP_KERNEL))
+ return VERR_NO_MEMORY;
+ cpumask_set_cpu(idCpu1, DstCpuMask);
+ cpumask_set_cpu(idCpu2, DstCpuMask);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
+ if (!alloc_cpumask_var(&DstCpuMask, GFP_KERNEL))
+ return VERR_NO_MEMORY;
+ cpumask_clear(DstCpuMask);
+ cpumask_set_cpu(idCpu1, DstCpuMask);
+ cpumask_set_cpu(idCpu2, DstCpuMask);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+ cpus_clear(DstCpuMask);
+ cpu_set(idCpu1, DstCpuMask);
+ cpu_set(idCpu2, DstCpuMask);
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
+ smp_call_function_many(DstCpuMask, rtmpLinuxWrapperPostInc, &Args, !fCallSelf /* wait */);
+ rc = 0;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+ rc = smp_call_function_mask(DstCpuMask, rtmpLinuxWrapperPostInc, &Args, !fCallSelf /* wait */);
+#else /* older kernels */
+ rc = smp_call_function(rtMpLinuxOnPairWrapper, &Args, 0 /* retry */, !fCallSelf /* wait */);
+#endif /* older kernels */
+ Assert(rc == 0);
+
+ /* Call ourselves if necessary and wait for the other party to be done. */
+ if (fCallSelf)
+ {
+ uint32_t cLoops = 0;
+ rtmpLinuxWrapper(&Args);
+ while (ASMAtomicReadU32(&Args.cHits) < 2)
+ {
+ if ((cLoops & 0x1ff) == 0 && !RTMpIsCpuOnline(idCpuSelf == idCpu1 ? idCpu2 : idCpu1))
+ break;
+ cLoops++;
+ ASMNopPause();
+ }
+ }
+
+ Assert(Args.cHits <= 2);
+ if (Args.cHits == 2)
+ rc = VINF_SUCCESS;
+ else if (Args.cHits == 1)
+ rc = VERR_NOT_ALL_CPUS_SHOWED;
+ else if (Args.cHits == 0)
+ rc = VERR_CPU_OFFLINE;
+ else
+ rc = VERR_CPU_IPE_1;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
+ free_cpumask_var(DstCpuMask);
+#endif
+ }
+ /*
+ * A CPU must be present to be considered just offline.
+ */
+ else if ( RTMpIsCpuPresent(idCpu1)
+ && RTMpIsCpuPresent(idCpu2))
+ rc = VERR_CPU_OFFLINE;
+ else
+ rc = VERR_CPU_NOT_FOUND;
+ RTThreadPreemptRestore(&PreemptState);;
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTMpOnPair);
+
+
+RTDECL(bool) RTMpOnPairIsConcurrentExecSupported(void)
+{
+ return true;
+}
+RT_EXPORT_SYMBOL(RTMpOnPairIsConcurrentExecSupported);
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+/**
+ * Wrapper between the native linux per-cpu callbacks and PFNRTWORKER
+ * employed by RTMpOnSpecific on older kernels that lacks smp_call_function_single.
+ *
+ * @param pvInfo Pointer to the RTMPARGS package.
+ */
+static void rtmpOnSpecificLinuxWrapper(void *pvInfo)
+{
+ PRTMPARGS pArgs = (PRTMPARGS)pvInfo;
+ RTCPUID idCpu = RTMpCpuId();
+
+ if (idCpu == pArgs->idCpu)
+ {
+ pArgs->pfnWorker(idCpu, pArgs->pvUser1, pArgs->pvUser2);
+ ASMAtomicIncU32(&pArgs->cHits);
+ }
+}
+#endif
+
+
+RTDECL(int) RTMpOnSpecific(RTCPUID idCpu, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+ int rc;
+ RTMPARGS Args;
+
+ RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
+ Args.pfnWorker = pfnWorker;
+ Args.pvUser1 = pvUser1;
+ Args.pvUser2 = pvUser2;
+ Args.idCpu = idCpu;
+ Args.cHits = 0;
+
+ if (!RTMpIsCpuPossible(idCpu))
+ return VERR_CPU_NOT_FOUND;
+
+ RTThreadPreemptDisable(&PreemptState);
+ if (idCpu != RTMpCpuId())
+ {
+ if (RTMpIsCpuOnline(idCpu))
+ {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+ rc = smp_call_function_single(idCpu, rtmpLinuxWrapper, &Args, 1 /* wait */);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
+ rc = smp_call_function_single(idCpu, rtmpLinuxWrapper, &Args, 0 /* retry */, 1 /* wait */);
+#else /* older kernels */
+ rc = smp_call_function(rtmpOnSpecificLinuxWrapper, &Args, 0 /* retry */, 1 /* wait */);
+#endif /* older kernels */
+ Assert(rc == 0);
+ rc = Args.cHits ? VINF_SUCCESS : VERR_CPU_OFFLINE;
+ }
+ else
+ rc = VERR_CPU_OFFLINE;
+ }
+ else
+ {
+ rtmpLinuxWrapper(&Args);
+ rc = VINF_SUCCESS;
+ }
+ RTThreadPreemptRestore(&PreemptState);;
+
+ NOREF(rc);
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTMpOnSpecific);
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
+/**
+ * Dummy callback used by RTMpPokeCpu.
+ *
+ * @param pvInfo Ignored.
+ */
+static void rtmpLinuxPokeCpuCallback(void *pvInfo)
+{
+ NOREF(pvInfo);
+}
+#endif
+
+
+RTDECL(int) RTMpPokeCpu(RTCPUID idCpu)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
+ int rc;
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ if (!RTMpIsCpuPossible(idCpu))
+ return VERR_CPU_NOT_FOUND;
+ if (!RTMpIsCpuOnline(idCpu))
+ return VERR_CPU_OFFLINE;
+
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+ rc = smp_call_function_single(idCpu, rtmpLinuxPokeCpuCallback, NULL, 0 /* wait */);
+# elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
+ rc = smp_call_function_single(idCpu, rtmpLinuxPokeCpuCallback, NULL, 0 /* retry */, 0 /* wait */);
+# else /* older kernels */
+# error oops
+# endif /* older kernels */
+ NOREF(rc);
+ Assert(rc == 0);
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+
+#else /* older kernels */
+ /* no unicast here? */
+ return VERR_NOT_SUPPORTED;
+#endif /* older kernels */
+}
+RT_EXPORT_SYMBOL(RTMpPokeCpu);
+
+
+RTDECL(bool) RTMpOnAllIsConcurrentSafe(void)
+{
+ return true;
+}
+RT_EXPORT_SYMBOL(RTMpOnAllIsConcurrentSafe);
+
--- /dev/null
+/* $Id: mpnotification-r0drv-linux.c $ */
+/** @file
+ * IPRT - Multiprocessor Event Notifications, Ring-0 Driver, Linux.
+ */
+
+/*
+ * Copyright (C) 2008-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "the-linux-kernel.h"
+#include "internal/iprt.h"
+
+#include <iprt/asm-amd64-x86.h>
+#include <iprt/err.h>
+#include <iprt/cpuset.h>
+#include <iprt/thread.h>
+#include "r0drv/mp-r0drv.h"
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
+
+static enum cpuhp_state g_rtR0MpOnline;
+
+/*
+ * Linux 4.10 completely removed CPU notifiers. So let's switch to CPU hotplug
+ * notification.
+ */
+
+static int rtR0MpNotificationLinuxOnline(unsigned int cpu)
+{
+ RTCPUID idCpu = RTMpCpuIdFromSetIndex(cpu);
+ rtMpNotificationDoCallbacks(RTMPEVENT_ONLINE, idCpu);
+ return 0;
+}
+
+static int rtR0MpNotificationLinuxOffline(unsigned int cpu)
+{
+ RTCPUID idCpu = RTMpCpuIdFromSetIndex(cpu);
+ rtMpNotificationDoCallbacks(RTMPEVENT_OFFLINE, idCpu);
+ return 0;
+}
+
+DECLHIDDEN(int) rtR0MpNotificationNativeInit(void)
+{
+ int rc;
+ IPRT_LINUX_SAVE_EFL_AC();
+ rc = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "vboxdrv:online",
+ rtR0MpNotificationLinuxOnline, rtR0MpNotificationLinuxOffline);
+ IPRT_LINUX_RESTORE_EFL_AC();
+ /*
+ * cpuhp_setup_state_nocalls() returns a positive state number for
+ * CPUHP_AP_ONLINE_DYN or -ENOSPC if there is no free slot available
+ * (see cpuhp_reserve_state / definition of CPUHP_AP_ONLINE_DYN).
+ */
+ AssertMsgReturn(rc > 0, ("%d\n", rc), RTErrConvertFromErrno(rc));
+ g_rtR0MpOnline = rc;
+ return VINF_SUCCESS;
+}
+
+
+DECLHIDDEN(void) rtR0MpNotificationNativeTerm(void)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+ cpuhp_remove_state_nocalls(g_rtR0MpOnline);
+ IPRT_LINUX_RESTORE_EFL_AC();
+}
+
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 71) && defined(CONFIG_SMP)
+
+static int rtMpNotificationLinuxCallback(struct notifier_block *pNotifierBlock, unsigned long ulNativeEvent, void *pvCpu);
+
+/**
+ * The notifier block we use for registering the callback.
+ */
+static struct notifier_block g_NotifierBlock =
+{
+ .notifier_call = rtMpNotificationLinuxCallback,
+ .next = NULL,
+ .priority = 0
+};
+
+# ifdef CPU_DOWN_FAILED
+/**
+ * The set of CPUs we've seen going offline recently.
+ */
+static RTCPUSET g_MpPendingOfflineSet;
+# endif
+
+
+/**
+ * The native callback.
+ *
+ * @returns NOTIFY_DONE.
+ * @param pNotifierBlock Pointer to g_NotifierBlock.
+ * @param ulNativeEvent The native event.
+ * @param pvCpu The cpu id cast into a pointer value.
+ *
+ * @remarks This can fire with preemption enabled and on any CPU.
+ */
+static int rtMpNotificationLinuxCallback(struct notifier_block *pNotifierBlock, unsigned long ulNativeEvent, void *pvCpu)
+{
+ bool fProcessEvent = false;
+ RTCPUID idCpu = (uintptr_t)pvCpu;
+ NOREF(pNotifierBlock);
+
+ /*
+ * Note that redhat/CentOS ported _some_ of the FROZEN macros
+ * back to their 2.6.18-92.1.10.el5 kernel but actually don't
+ * use them. Thus we have to test for both CPU_TASKS_FROZEN and
+ * the individual event variants.
+ */
+ switch (ulNativeEvent)
+ {
+ /*
+ * Pick up online events or failures to go offline.
+ * Ignore failure events for CPUs we didn't see go offline.
+ */
+# ifdef CPU_DOWN_FAILED
+ case CPU_DOWN_FAILED:
+# if defined(CPU_TASKS_FROZEN) && defined(CPU_DOWN_FAILED_FROZEN)
+ case CPU_DOWN_FAILED_FROZEN:
+# endif
+ if (!RTCpuSetIsMember(&g_MpPendingOfflineSet, idCpu))
+ break; /* fProcessEvents = false */
+ /* fall thru */
+# endif
+ case CPU_ONLINE:
+# if defined(CPU_TASKS_FROZEN) && defined(CPU_ONLINE_FROZEN)
+ case CPU_ONLINE_FROZEN:
+# endif
+# ifdef CPU_DOWN_FAILED
+ RTCpuSetDel(&g_MpPendingOfflineSet, idCpu);
+# endif
+ fProcessEvent = true;
+ break;
+
+ /*
+ * Pick the earliest possible offline event.
+ * The only important thing here is that we get the event and that
+ * it's exactly one.
+ */
+# ifdef CPU_DOWN_PREPARE
+ case CPU_DOWN_PREPARE:
+# if defined(CPU_TASKS_FROZEN) && defined(CPU_DOWN_PREPARE_FROZEN)
+ case CPU_DOWN_PREPARE_FROZEN:
+# endif
+ fProcessEvent = true;
+# else
+ case CPU_DEAD:
+# if defined(CPU_TASKS_FROZEN) && defined(CPU_DEAD_FROZEN)
+ case CPU_DEAD_FROZEN:
+# endif
+ /* Don't process CPU_DEAD notifications. */
+# endif
+# ifdef CPU_DOWN_FAILED
+ RTCpuSetAdd(&g_MpPendingOfflineSet, idCpu);
+# endif
+ break;
+ }
+
+ if (!fProcessEvent)
+ return NOTIFY_DONE;
+
+ switch (ulNativeEvent)
+ {
+# ifdef CPU_DOWN_FAILED
+ case CPU_DOWN_FAILED:
+# if defined(CPU_TASKS_FROZEN) && defined(CPU_DOWN_FAILED_FROZEN)
+ case CPU_DOWN_FAILED_FROZEN:
+# endif
+# endif
+ case CPU_ONLINE:
+# if defined(CPU_TASKS_FROZEN) && defined(CPU_ONLINE_FROZEN)
+ case CPU_ONLINE_FROZEN:
+# endif
+ rtMpNotificationDoCallbacks(RTMPEVENT_ONLINE, idCpu);
+ break;
+
+# ifdef CPU_DOWN_PREPARE
+ case CPU_DOWN_PREPARE:
+# if defined(CPU_TASKS_FROZEN) && defined(CPU_DOWN_PREPARE_FROZEN)
+ case CPU_DOWN_PREPARE_FROZEN:
+# endif
+ rtMpNotificationDoCallbacks(RTMPEVENT_OFFLINE, idCpu);
+ break;
+# endif
+ }
+
+ return NOTIFY_DONE;
+}
+
+
+DECLHIDDEN(int) rtR0MpNotificationNativeInit(void)
+{
+ int rc;
+ IPRT_LINUX_SAVE_EFL_AC();
+
+# ifdef CPU_DOWN_FAILED
+ RTCpuSetEmpty(&g_MpPendingOfflineSet);
+# endif
+
+ rc = register_cpu_notifier(&g_NotifierBlock);
+ IPRT_LINUX_RESTORE_EFL_AC();
+ AssertMsgReturn(!rc, ("%d\n", rc), RTErrConvertFromErrno(rc));
+ return VINF_SUCCESS;
+}
+
+
+DECLHIDDEN(void) rtR0MpNotificationNativeTerm(void)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+ unregister_cpu_notifier(&g_NotifierBlock);
+ IPRT_LINUX_RESTORE_EFL_AC();
+}
+
+#else /* Not supported / Not needed */
+
+DECLHIDDEN(int) rtR0MpNotificationNativeInit(void)
+{
+ return VINF_SUCCESS;
+}
+
+DECLHIDDEN(void) rtR0MpNotificationNativeTerm(void)
+{
+}
+
+#endif /* Not supported / Not needed */
+
--- /dev/null
+/* $Id: process-r0drv-linux.c $ */
+/** @file
+ * IPRT - Process, Ring-0 Driver, Linux.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "the-linux-kernel.h"
+#include "internal/iprt.h"
+
+#include <iprt/process.h>
+
+
+RTDECL(RTPROCESS) RTProcSelf(void)
+{
+ return (RTPROCESS)current->tgid;
+}
+RT_EXPORT_SYMBOL(RTProcSelf);
+
+
+RTR0DECL(RTR0PROCESS) RTR0ProcHandleSelf(void)
+{
+ return (RTR0PROCESS)current->tgid;
+}
+RT_EXPORT_SYMBOL(RTR0ProcHandleSelf);
+
--- /dev/null
+/* $Id: semevent-r0drv-linux.c $ */
+/** @file
+ * IPRT - Single Release Event Semaphores, Ring-0 Driver, Linux.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define RTSEMEVENT_WITHOUT_REMAPPING
+#include "the-linux-kernel.h"
+#include "internal/iprt.h"
+#include <iprt/semaphore.h>
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/lockvalidator.h>
+#include <iprt/mem.h>
+
+#include "waitqueue-r0drv-linux.h"
+#include "internal/magics.h"
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * Linux event semaphore.
+ */
+typedef struct RTSEMEVENTINTERNAL
+{
+ /** Magic value (RTSEMEVENT_MAGIC). */
+ uint32_t volatile u32Magic;
+ /** The object status - !0 when signaled and 0 when reset. */
+ uint32_t volatile fState;
+ /** Reference counter. */
+ uint32_t volatile cRefs;
+ /** The wait queue. */
+ wait_queue_head_t Head;
+} RTSEMEVENTINTERNAL, *PRTSEMEVENTINTERNAL;
+
+
+
+RTDECL(int) RTSemEventCreate(PRTSEMEVENT phEventSem)
+{
+ return RTSemEventCreateEx(phEventSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL);
+}
+
+
+RTDECL(int) RTSemEventCreateEx(PRTSEMEVENT phEventSem, uint32_t fFlags, RTLOCKVALCLASS hClass, const char *pszNameFmt, ...)
+{
+ PRTSEMEVENTINTERNAL pThis;
+ IPRT_LINUX_SAVE_EFL_AC();
+ RT_NOREF_PV(hClass); RT_NOREF_PV(pszNameFmt);
+
+ AssertReturn(!(fFlags & ~(RTSEMEVENT_FLAGS_NO_LOCK_VAL | RTSEMEVENT_FLAGS_BOOTSTRAP_HACK)), VERR_INVALID_PARAMETER);
+ Assert(!(fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK) || (fFlags & RTSEMEVENT_FLAGS_NO_LOCK_VAL));
+
+ pThis = (PRTSEMEVENTINTERNAL)RTMemAlloc(sizeof(*pThis));
+ if (!pThis)
+ return VERR_NO_MEMORY;
+
+ pThis->u32Magic = RTSEMEVENT_MAGIC;
+ pThis->fState = 0;
+ pThis->cRefs = 1;
+ init_waitqueue_head(&pThis->Head);
+
+ *phEventSem = pThis;
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTSemEventCreate);
+
+
+/**
+ * Retains a reference to the event semaphore.
+ *
+ * @param pThis The event semaphore.
+ */
+DECLINLINE(void) rtR0SemEventLnxRetain(PRTSEMEVENTINTERNAL pThis)
+{
+ uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
+ Assert(cRefs < 100000); NOREF(cRefs);
+}
+
+
+/**
+ * Releases a reference to the event semaphore.
+ *
+ * @param pThis The event semaphore.
+ */
+DECLINLINE(void) rtR0SemEventLnxRelease(PRTSEMEVENTINTERNAL pThis)
+{
+ if (RT_UNLIKELY(ASMAtomicDecU32(&pThis->cRefs) == 0))
+ RTMemFree(pThis);
+}
+
+
+RTDECL(int) RTSemEventDestroy(RTSEMEVENT hEventSem)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ /*
+ * Validate input.
+ */
+ PRTSEMEVENTINTERNAL pThis = hEventSem;
+ if (pThis == NIL_RTSEMEVENT)
+ return VINF_SUCCESS;
+ AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
+ Assert(pThis->cRefs > 0);
+
+ /*
+ * Invalidate it and signal the object just in case.
+ */
+ ASMAtomicWriteU32(&pThis->u32Magic, ~RTSEMEVENT_MAGIC);
+ ASMAtomicWriteU32(&pThis->fState, 0);
+ Assert(!waitqueue_active(&pThis->Head));
+ wake_up_all(&pThis->Head);
+ rtR0SemEventLnxRelease(pThis);
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTSemEventDestroy);
+
+
+RTDECL(int) RTSemEventSignal(RTSEMEVENT hEventSem)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ /*
+ * Validate input.
+ */
+ PRTSEMEVENTINTERNAL pThis = (PRTSEMEVENTINTERNAL)hEventSem;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
+ rtR0SemEventLnxRetain(pThis);
+
+ /*
+ * Signal the event object.
+ */
+ ASMAtomicWriteU32(&pThis->fState, 1);
+ wake_up(&pThis->Head);
+
+ rtR0SemEventLnxRelease(pThis);
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTSemEventSignal);
+
+
+/**
+ * Worker for RTSemEventWaitEx and RTSemEventWaitExDebug.
+ *
+ * @returns VBox status code.
+ * @param pThis The event semaphore.
+ * @param fFlags See RTSemEventWaitEx.
+ * @param uTimeout See RTSemEventWaitEx.
+ * @param pSrcPos The source code position of the wait.
+ */
+static int rtR0SemEventLnxWait(PRTSEMEVENTINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout,
+ PCRTLOCKVALSRCPOS pSrcPos)
+{
+ int rc;
+ RT_NOREF_PV(pSrcPos);
+
+ /*
+ * Validate the input.
+ */
+ AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
+ AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
+ AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
+ rtR0SemEventLnxRetain(pThis);
+
+ /*
+ * Try grab the event without setting up the wait.
+ */
+ if ( 1 /** @todo check if there are someone waiting already - waitqueue_active, but then what do we do below? */
+ && ASMAtomicCmpXchgU32(&pThis->fState, 0, 1))
+ rc = VINF_SUCCESS;
+ else
+ {
+ /*
+ * We have to wait.
+ */
+ IPRT_LINUX_SAVE_EFL_AC();
+ RTR0SEMLNXWAIT Wait;
+ rc = rtR0SemLnxWaitInit(&Wait, fFlags, uTimeout, &pThis->Head);
+ if (RT_SUCCESS(rc))
+ {
+ IPRT_DEBUG_SEMS_STATE(pThis, 'E');
+ for (;;)
+ {
+ /* The destruction test. */
+ if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENT_MAGIC))
+ rc = VERR_SEM_DESTROYED;
+ else
+ {
+ rtR0SemLnxWaitPrepare(&Wait);
+
+ /* Check the exit conditions. */
+ if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENT_MAGIC))
+ rc = VERR_SEM_DESTROYED;
+ else if (ASMAtomicCmpXchgU32(&pThis->fState, 0, 1))
+ rc = VINF_SUCCESS;
+ else if (rtR0SemLnxWaitHasTimedOut(&Wait))
+ rc = VERR_TIMEOUT;
+ else if (rtR0SemLnxWaitWasInterrupted(&Wait))
+ rc = VERR_INTERRUPTED;
+ else
+ {
+ /* Do the wait and then recheck the conditions. */
+ rtR0SemLnxWaitDoIt(&Wait);
+ continue;
+ }
+ }
+ break;
+ }
+
+ rtR0SemLnxWaitDelete(&Wait);
+ IPRT_DEBUG_SEMS_STATE_RC(pThis, 'E', rc);
+ }
+ IPRT_LINUX_RESTORE_EFL_AC();
+ }
+
+ rtR0SemEventLnxRelease(pThis);
+ return rc;
+}
+
+
+RTDECL(int) RTSemEventWaitEx(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout)
+{
+#ifndef RTSEMEVENT_STRICT
+ return rtR0SemEventLnxWait(hEventSem, fFlags, uTimeout, NULL);
+#else
+ RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
+ return rtR0SemEventLnxWait(hEventSem, fFlags, uTimeout, &SrcPos);
+#endif
+}
+RT_EXPORT_SYMBOL(RTSemEventWaitEx);
+
+
+RTDECL(int) RTSemEventWaitExDebug(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout,
+ RTHCUINTPTR uId, RT_SRC_POS_DECL)
+{
+ RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
+ return rtR0SemEventLnxWait(hEventSem, fFlags, uTimeout, &SrcPos);
+}
+RT_EXPORT_SYMBOL(RTSemEventWaitExDebug);
+
+
+RTDECL(uint32_t) RTSemEventGetResolution(void)
+{
+ return rtR0SemLnxWaitGetResolution();
+}
+RT_EXPORT_SYMBOL(RTSemEventGetResolution);
+
--- /dev/null
+/* $Id: semeventmulti-r0drv-linux.c $ */
+/** @file
+ * IPRT - Multiple Release Event Semaphores, Ring-0 Driver, Linux.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define RTSEMEVENTMULTI_WITHOUT_REMAPPING
+#include "the-linux-kernel.h"
+#include "internal/iprt.h"
+#include <iprt/semaphore.h>
+
+#include <iprt/assert.h>
+#include <iprt/asm.h>
+#include <iprt/err.h>
+#include <iprt/mem.h>
+#include <iprt/lockvalidator.h>
+
+#include "waitqueue-r0drv-linux.h"
+#include "internal/magics.h"
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/** @name fStateAndGen values
+ * @{ */
+/** The state bit number. */
+#define RTSEMEVENTMULTILNX_STATE_BIT 0
+/** The state mask. */
+#define RTSEMEVENTMULTILNX_STATE_MASK RT_BIT_32(RTSEMEVENTMULTILNX_STATE_BIT)
+/** The generation mask. */
+#define RTSEMEVENTMULTILNX_GEN_MASK ~RTSEMEVENTMULTILNX_STATE_MASK
+/** The generation shift. */
+#define RTSEMEVENTMULTILNX_GEN_SHIFT 1
+/** The initial variable value. */
+#define RTSEMEVENTMULTILNX_STATE_GEN_INIT UINT32_C(0xfffffffc)
+/** @} */
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * Linux event semaphore.
+ */
+typedef struct RTSEMEVENTMULTIINTERNAL
+{
+ /** Magic value (RTSEMEVENTMULTI_MAGIC). */
+ uint32_t volatile u32Magic;
+ /** The object state bit and generation counter.
+ * The generation counter is incremented every time the object is
+ * signalled. */
+ uint32_t volatile fStateAndGen;
+ /** Reference counter. */
+ uint32_t volatile cRefs;
+ /** The wait queue. */
+ wait_queue_head_t Head;
+} RTSEMEVENTMULTIINTERNAL, *PRTSEMEVENTMULTIINTERNAL;
+
+
+
+
+
+RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI phEventMultiSem)
+{
+ return RTSemEventMultiCreateEx(phEventMultiSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL);
+}
+
+
+RTDECL(int) RTSemEventMultiCreateEx(PRTSEMEVENTMULTI phEventMultiSem, uint32_t fFlags, RTLOCKVALCLASS hClass,
+ const char *pszNameFmt, ...)
+{
+ PRTSEMEVENTMULTIINTERNAL pThis;
+ IPRT_LINUX_SAVE_EFL_AC();
+ RT_NOREF_PV(hClass); RT_NOREF_PV(pszNameFmt);
+
+ AssertReturn(!(fFlags & ~RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
+ pThis = (PRTSEMEVENTMULTIINTERNAL)RTMemAlloc(sizeof(*pThis));
+ if (pThis)
+ {
+ pThis->u32Magic = RTSEMEVENTMULTI_MAGIC;
+ pThis->fStateAndGen = RTSEMEVENTMULTILNX_STATE_GEN_INIT;
+ pThis->cRefs = 1;
+ init_waitqueue_head(&pThis->Head);
+
+ *phEventMultiSem = pThis;
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+ }
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VERR_NO_MEMORY;
+}
+RT_EXPORT_SYMBOL(RTSemEventMultiCreate);
+
+
+/**
+ * Retain a reference to the semaphore.
+ *
+ * @param pThis The semaphore.
+ */
+DECLINLINE(void) rtR0SemEventMultiLnxRetain(PRTSEMEVENTMULTIINTERNAL pThis)
+{
+ uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
+ NOREF(cRefs);
+ Assert(cRefs && cRefs < 100000);
+}
+
+
+/**
+ * Release a reference, destroy the thing if necessary.
+ *
+ * @param pThis The semaphore.
+ */
+DECLINLINE(void) rtR0SemEventMultiLnxRelease(PRTSEMEVENTMULTIINTERNAL pThis)
+{
+ if (RT_UNLIKELY(ASMAtomicDecU32(&pThis->cRefs) == 0))
+ {
+ Assert(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC);
+ RTMemFree(pThis);
+ }
+}
+
+
+RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ /*
+ * Validate input.
+ */
+ PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
+ if (pThis == NIL_RTSEMEVENTMULTI)
+ return VINF_SUCCESS;
+ AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
+ AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
+ Assert(pThis->cRefs > 0);
+
+ /*
+ * Invalidate it and signal the object just in case.
+ */
+ ASMAtomicWriteU32(&pThis->u32Magic, ~RTSEMEVENTMULTI_MAGIC);
+ ASMAtomicAndU32(&pThis->fStateAndGen, RTSEMEVENTMULTILNX_GEN_MASK);
+ Assert(!waitqueue_active(&pThis->Head));
+ wake_up_all(&pThis->Head);
+ rtR0SemEventMultiLnxRelease(pThis);
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTSemEventMultiDestroy);
+
+
+RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+ uint32_t fNew;
+ uint32_t fOld;
+
+ /*
+ * Validate input.
+ */
+ PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
+ if (!pThis)
+ return VERR_INVALID_PARAMETER;
+ AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
+ AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
+ rtR0SemEventMultiLnxRetain(pThis);
+
+ /*
+ * Signal the event object. The cause of the paranoia here is racing to try
+ * deal with racing RTSemEventMultiSignal calls (should probably be
+ * forbidden, but it's relatively easy to handle).
+ */
+ do
+ {
+ fNew = fOld = ASMAtomicUoReadU32(&pThis->fStateAndGen);
+ fNew += 1 << RTSEMEVENTMULTILNX_GEN_SHIFT;
+ fNew |= RTSEMEVENTMULTILNX_STATE_MASK;
+ }
+ while (!ASMAtomicCmpXchgU32(&pThis->fStateAndGen, fNew, fOld));
+
+ wake_up_all(&pThis->Head);
+
+ rtR0SemEventMultiLnxRelease(pThis);
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTSemEventMultiSignal);
+
+
+RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem)
+{
+ /*
+ * Validate input.
+ */
+ PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
+ if (!pThis)
+ return VERR_INVALID_PARAMETER;
+ AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
+ AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
+ rtR0SemEventMultiLnxRetain(pThis);
+
+ /*
+ * Reset it.
+ */
+ ASMAtomicAndU32(&pThis->fStateAndGen, ~RTSEMEVENTMULTILNX_STATE_MASK);
+
+ rtR0SemEventMultiLnxRelease(pThis);
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTSemEventMultiReset);
+
+
+/**
+ * Worker for RTSemEventMultiWaitEx and RTSemEventMultiWaitExDebug.
+ *
+ * @returns VBox status code.
+ * @param pThis The event semaphore.
+ * @param fFlags See RTSemEventMultiWaitEx.
+ * @param uTimeout See RTSemEventMultiWaitEx.
+ * @param pSrcPos The source code position of the wait.
+ */
+static int rtR0SemEventMultiLnxWait(PRTSEMEVENTMULTIINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout,
+ PCRTLOCKVALSRCPOS pSrcPos)
+{
+ uint32_t fOrgStateAndGen;
+ int rc;
+ RT_NOREF_PV(pSrcPos);
+
+ /*
+ * Validate the input.
+ */
+ AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
+ AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
+ AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
+ rtR0SemEventMultiLnxRetain(pThis);
+
+ /*
+ * Is the event already signalled or do we have to wait?
+ */
+ fOrgStateAndGen = ASMAtomicUoReadU32(&pThis->fStateAndGen);
+ if (fOrgStateAndGen & RTSEMEVENTMULTILNX_STATE_MASK)
+ rc = VINF_SUCCESS;
+ else
+ {
+ /*
+ * We have to wait.
+ */
+ RTR0SEMLNXWAIT Wait;
+ IPRT_LINUX_SAVE_EFL_AC();
+ rc = rtR0SemLnxWaitInit(&Wait, fFlags, uTimeout, &pThis->Head);
+ if (RT_SUCCESS(rc))
+ {
+ IPRT_DEBUG_SEMS_STATE(pThis, 'E');
+ for (;;)
+ {
+ /* The destruction test. */
+ if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
+ rc = VERR_SEM_DESTROYED;
+ else
+ {
+ rtR0SemLnxWaitPrepare(&Wait);
+
+ /* Check the exit conditions. */
+ if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
+ rc = VERR_SEM_DESTROYED;
+ else if (ASMAtomicUoReadU32(&pThis->fStateAndGen) != fOrgStateAndGen)
+ rc = VINF_SUCCESS;
+ else if (rtR0SemLnxWaitHasTimedOut(&Wait))
+ rc = VERR_TIMEOUT;
+ else if (rtR0SemLnxWaitWasInterrupted(&Wait))
+ rc = VERR_INTERRUPTED;
+ else
+ {
+ /* Do the wait and then recheck the conditions. */
+ rtR0SemLnxWaitDoIt(&Wait);
+ continue;
+ }
+ }
+ break;
+ }
+
+ rtR0SemLnxWaitDelete(&Wait);
+ IPRT_DEBUG_SEMS_STATE_RC(pThis, 'E', rc);
+ }
+ IPRT_LINUX_RESTORE_EFL_AC();
+ }
+
+ rtR0SemEventMultiLnxRelease(pThis);
+ return rc;
+}
+
+
+RTDECL(int) RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout)
+{
+#ifndef RTSEMEVENT_STRICT
+ return rtR0SemEventMultiLnxWait(hEventMultiSem, fFlags, uTimeout, NULL);
+#else
+ RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
+ return rtR0SemEventMultiLnxWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
+#endif
+}
+RT_EXPORT_SYMBOL(RTSemEventMultiWaitEx);
+
+
+RTDECL(int) RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout,
+ RTHCUINTPTR uId, RT_SRC_POS_DECL)
+{
+ RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
+ return rtR0SemEventMultiLnxWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
+}
+RT_EXPORT_SYMBOL(RTSemEventMultiWaitExDebug);
+
+
+RTDECL(uint32_t) RTSemEventMultiGetResolution(void)
+{
+ return rtR0SemLnxWaitGetResolution();
+}
+RT_EXPORT_SYMBOL(RTSemEventMultiGetResolution);
+
--- /dev/null
+/* $Id: semfastmutex-r0drv-linux.c $ */
+/** @file
+ * IPRT - Fast Mutex Semaphores, Ring-0 Driver, Linux.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "the-linux-kernel.h"
+#include "internal/iprt.h"
+#include <iprt/semaphore.h>
+#include <iprt/alloc.h>
+#include <iprt/assert.h>
+#include <iprt/asm.h>
+#include <iprt/err.h>
+#if defined(RT_STRICT) || defined(IPRT_DEBUG_SEMS)
+# include <iprt/thread.h>
+#endif
+
+#include "internal/magics.h"
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * Wrapper for the linux semaphore structure.
+ */
+typedef struct RTSEMFASTMUTEXINTERNAL
+{
+ /** Magic value (RTSEMFASTMUTEX_MAGIC). */
+ uint32_t u32Magic;
+ /** the linux semaphore. */
+ struct semaphore Semaphore;
+#if defined(RT_STRICT) || defined(IPRT_DEBUG_SEMS)
+ /** For check. */
+ RTNATIVETHREAD volatile Owner;
+#endif
+} RTSEMFASTMUTEXINTERNAL, *PRTSEMFASTMUTEXINTERNAL;
+
+
+RTDECL(int) RTSemFastMutexCreate(PRTSEMFASTMUTEX phFastMtx)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ /*
+ * Allocate.
+ */
+ PRTSEMFASTMUTEXINTERNAL pThis;
+ pThis = (PRTSEMFASTMUTEXINTERNAL)RTMemAlloc(sizeof(*pThis));
+ if (!pThis)
+ return VERR_NO_MEMORY;
+
+ /*
+ * Initialize.
+ */
+ pThis->u32Magic = RTSEMFASTMUTEX_MAGIC;
+ sema_init(&pThis->Semaphore, 1);
+#if defined(RT_STRICT) || defined(IPRT_DEBUG_SEMS)
+ pThis->Owner = NIL_RTNATIVETHREAD;
+#endif
+
+ *phFastMtx = pThis;
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTSemFastMutexCreate);
+
+
+RTDECL(int) RTSemFastMutexDestroy(RTSEMFASTMUTEX hFastMtx)
+{
+ /*
+ * Validate.
+ */
+ PRTSEMFASTMUTEXINTERNAL pThis = hFastMtx;
+ if (pThis == NIL_RTSEMFASTMUTEX)
+ return VINF_SUCCESS;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertMsgReturn(pThis->u32Magic == RTSEMFASTMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
+
+ ASMAtomicWriteU32(&pThis->u32Magic, RTSEMFASTMUTEX_MAGIC_DEAD);
+ RTMemFree(pThis);
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTSemFastMutexDestroy);
+
+
+RTDECL(int) RTSemFastMutexRequest(RTSEMFASTMUTEX hFastMtx)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ /*
+ * Validate.
+ */
+ PRTSEMFASTMUTEXINTERNAL pThis = hFastMtx;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertMsgReturn(pThis->u32Magic == RTSEMFASTMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
+
+ IPRT_DEBUG_SEMS_STATE(pThis, 'd');
+ down(&pThis->Semaphore);
+#if defined(RT_STRICT) || defined(IPRT_DEBUG_SEMS)
+ IPRT_DEBUG_SEMS_STATE(pThis, 'o');
+ AssertRelease(pThis->Owner == NIL_RTNATIVETHREAD);
+ ASMAtomicUoWriteSize(&pThis->Owner, RTThreadNativeSelf());
+#endif
+
+ IPRT_LINUX_RESTORE_EFL_ONLY_AC();
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTSemFastMutexRequest);
+
+
+RTDECL(int) RTSemFastMutexRelease(RTSEMFASTMUTEX hFastMtx)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ /*
+ * Validate.
+ */
+ PRTSEMFASTMUTEXINTERNAL pThis = hFastMtx;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertMsgReturn(pThis->u32Magic == RTSEMFASTMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
+
+#if defined(RT_STRICT) || defined(IPRT_DEBUG_SEMS)
+ AssertRelease(pThis->Owner == RTThreadNativeSelf());
+ ASMAtomicUoWriteSize(&pThis->Owner, NIL_RTNATIVETHREAD);
+#endif
+ up(&pThis->Semaphore);
+ IPRT_DEBUG_SEMS_STATE(pThis, 'u');
+
+ IPRT_LINUX_RESTORE_EFL_ONLY_AC();
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTSemFastMutexRelease);
+
--- /dev/null
+/* $Id: semmutex-r0drv-linux.c $ */
+/** @file
+ * IPRT - Mutex Semaphores, Ring-0 Driver, Linux.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define RTSEMMUTEX_WITHOUT_REMAPPING
+#include "the-linux-kernel.h"
+#include "internal/iprt.h"
+#include <iprt/semaphore.h>
+
+#include <iprt/assert.h>
+#include <iprt/asm.h>
+#include <iprt/mem.h>
+#include <iprt/err.h>
+#include <iprt/list.h>
+
+#include "internal/magics.h"
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+typedef struct RTSEMMUTEXLNXWAITER
+{
+ /** The list entry. */
+ RTLISTNODE ListEntry;
+ /** The waiting task. */
+ struct task_struct *pTask;
+ /** Why did we wake up? */
+ enum
+ {
+ /** Wakeup to take the semaphore. */
+ RTSEMMUTEXLNXWAITER_WAKEUP,
+ /** Mutex is being destroyed. */
+ RTSEMMUTEXLNXWAITER_DESTROYED,
+ /** Some other reason. */
+ RTSEMMUTEXLNXWAITER_OTHER
+ } volatile enmReason;
+} RTSEMMUTEXLNXWAITER, *PRTSEMMUTEXLNXWAITER;
+
+/**
+ * Wrapper for the linux semaphore structure.
+ */
+typedef struct RTSEMMUTEXINTERNAL
+{
+ /** Magic value (RTSEMMUTEX_MAGIC). */
+ uint32_t u32Magic;
+ /** The number of recursions. */
+ uint32_t cRecursions;
+ /** The list of waiting threads. */
+ RTLISTANCHOR WaiterList;
+ /** The current owner, NULL if none. */
+ struct task_struct *pOwnerTask;
+ /** The number of references to this piece of memory. This is used to
+ * prevent it from being kicked from underneath us while waiting. */
+ uint32_t volatile cRefs;
+ /** The spinlock protecting the members and falling asleep. */
+ spinlock_t Spinlock;
+} RTSEMMUTEXINTERNAL, *PRTSEMMUTEXINTERNAL;
+
+
+RTDECL(int) RTSemMutexCreate(PRTSEMMUTEX phMtx)
+{
+ int rc = VINF_SUCCESS;
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ /*
+ * Allocate.
+ */
+ PRTSEMMUTEXINTERNAL pThis;
+ pThis = (PRTSEMMUTEXINTERNAL)RTMemAlloc(sizeof(*pThis));
+ if (pThis)
+ {
+ /*
+ * Initialize.
+ */
+ pThis->u32Magic = RTSEMMUTEX_MAGIC;
+ pThis->cRecursions = 0;
+ pThis->pOwnerTask = NULL;
+ pThis->cRefs = 1;
+ RTListInit(&pThis->WaiterList);
+ spin_lock_init(&pThis->Spinlock);
+
+ *phMtx = pThis;
+ }
+ else
+ rc = VERR_NO_MEMORY;
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTSemMutexCreate);
+
+
+RTDECL(int) RTSemMutexDestroy(RTSEMMUTEX hMtx)
+{
+ PRTSEMMUTEXINTERNAL pThis = hMtx;
+ PRTSEMMUTEXLNXWAITER pCur;
+ unsigned long fSavedIrq;
+
+ /*
+ * Validate.
+ */
+ if (pThis == NIL_RTSEMMUTEX)
+ return VINF_SUCCESS;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
+
+ /*
+ * Kill it, kick waiters and release it.
+ */
+ AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, RTSEMMUTEX_MAGIC_DEAD, RTSEMMUTEX_MAGIC), VERR_INVALID_HANDLE);
+
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ spin_lock_irqsave(&pThis->Spinlock, fSavedIrq);
+ RTListForEach(&pThis->WaiterList, pCur, RTSEMMUTEXLNXWAITER, ListEntry)
+ {
+ pCur->enmReason = RTSEMMUTEXLNXWAITER_DESTROYED;
+ wake_up_process(pCur->pTask);
+ }
+
+ if (ASMAtomicDecU32(&pThis->cRefs) != 0)
+ spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq);
+ else
+ {
+ spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq);
+ RTMemFree(pThis);
+ }
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTSemMutexDestroy);
+
+
+/**
+ * Worker for rtSemMutexLinuxRequest that handles the case where we go to sleep.
+ *
+ * @returns VINF_SUCCESS, VERR_INTERRUPTED, VERR_TIMEOUT or VERR_SEM_DESTROYED.
+ * Returns without owning the spinlock.
+ * @param pThis The mutex instance.
+ * @param cMillies The timeout.
+ * @param fInterruptible The wait type.
+ * @param fSavedIrq The saved IRQ flags.
+ */
+static int rtSemMutexLinuxRequestSleep(PRTSEMMUTEXINTERNAL pThis, RTMSINTERVAL cMillies,
+ bool fInterruptible, unsigned long fSavedIrq)
+{
+ struct task_struct *pSelf = current;
+ int rc = VERR_TIMEOUT;
+ long lTimeout = cMillies == RT_INDEFINITE_WAIT ? MAX_SCHEDULE_TIMEOUT : msecs_to_jiffies(cMillies);
+ RTSEMMUTEXLNXWAITER Waiter;
+
+ IPRT_DEBUG_SEMS_STATE(pThis, 'm');
+
+ /*
+ * Grab a reference to the mutex and add ourselves to the waiter list.
+ */
+ ASMAtomicIncU32(&pThis->cRefs);
+
+ Waiter.pTask = pSelf;
+ Waiter.enmReason = RTSEMMUTEXLNXWAITER_OTHER;
+ RTListAppend(&pThis->WaiterList, &Waiter.ListEntry);
+
+ /*
+ * Do the waiting.
+ */
+ for (;;)
+ {
+ /* Check signal and timeout conditions. */
+ if ( fInterruptible
+ && signal_pending(pSelf))
+ {
+ rc = VERR_INTERRUPTED;
+ break;
+ }
+
+ if (!lTimeout)
+ break;
+
+ /* Go to sleep. */
+ set_current_state(fInterruptible ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
+ spin_unlock_irq(&pThis->Spinlock);
+
+ lTimeout = schedule_timeout(lTimeout);
+
+ spin_lock_irq(&pThis->Spinlock);
+ set_current_state(TASK_RUNNING);
+
+ /* Did someone wake us up? */
+ if (Waiter.enmReason == RTSEMMUTEXLNXWAITER_WAKEUP)
+ {
+ Assert(pThis->cRecursions == 0);
+ pThis->cRecursions = 1;
+ pThis->pOwnerTask = pSelf;
+ rc = VINF_SUCCESS;
+ break;
+ }
+
+ /* Is the mutex being destroyed? */
+ if (RT_UNLIKELY( Waiter.enmReason == RTSEMMUTEXLNXWAITER_DESTROYED
+ || pThis->u32Magic != RTSEMMUTEX_MAGIC))
+ {
+ rc = VERR_SEM_DESTROYED;
+ break;
+ }
+ }
+
+ /*
+ * Unlink ourself from the waiter list, dereference the mutex and exit the
+ * lock. We might have to free the mutex if it was the destroyed.
+ */
+ RTListNodeRemove(&Waiter.ListEntry);
+ IPRT_DEBUG_SEMS_STATE_RC(pThis, 'M', rc);
+
+ if (RT_LIKELY(ASMAtomicDecU32(&pThis->cRefs) != 0))
+ spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq);
+ else
+ {
+ Assert(RT_FAILURE_NP(rc));
+ spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq);
+ RTMemFree(pThis);
+ }
+ return rc;
+}
+
+
+/**
+ * Internal worker.
+ */
+DECLINLINE(int) rtSemMutexLinuxRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, bool fInterruptible)
+{
+ PRTSEMMUTEXINTERNAL pThis = hMutexSem;
+ struct task_struct *pSelf = current;
+ unsigned long fSavedIrq;
+ int rc;
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ /*
+ * Validate.
+ */
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
+ Assert(pThis->cRefs >= 1);
+
+ /*
+ * Lock it and check if it's a recursion.
+ */
+ spin_lock_irqsave(&pThis->Spinlock, fSavedIrq);
+ if (pThis->pOwnerTask == pSelf)
+ {
+ pThis->cRecursions++;
+ Assert(pThis->cRecursions > 1);
+ Assert(pThis->cRecursions < 256);
+ rc = VINF_SUCCESS;
+ }
+ /*
+ * Not a recursion, maybe it's not owned by anyone then?
+ */
+ else if ( pThis->pOwnerTask == NULL
+ && RTListIsEmpty(&pThis->WaiterList))
+ {
+ Assert(pThis->cRecursions == 0);
+ pThis->cRecursions = 1;
+ pThis->pOwnerTask = pSelf;
+ rc = VINF_SUCCESS;
+ }
+ /*
+ * Was it a polling call?
+ */
+ else if (cMillies == 0)
+ rc = VERR_TIMEOUT;
+ /*
+ * No, so go to sleep.
+ */
+ else
+ {
+ rc = rtSemMutexLinuxRequestSleep(pThis, cMillies, fInterruptible, fSavedIrq);
+ IPRT_LINUX_RESTORE_EFL_ONLY_AC();
+ return rc;
+ }
+
+ IPRT_DEBUG_SEMS_STATE_RC(pThis, 'M', rc);
+ spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq);
+ IPRT_LINUX_RESTORE_EFL_ONLY_AC();
+ return rc;
+}
+
+
+RTDECL(int) RTSemMutexRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies)
+{
+ return rtSemMutexLinuxRequest(hMutexSem, cMillies, false /*fInterruptible*/);
+}
+RT_EXPORT_SYMBOL(RTSemMutexRequest);
+
+
+RTDECL(int) RTSemMutexRequestDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
+{
+ RT_NOREF_PV(uId); RT_SRC_POS_NOREF();
+ return RTSemMutexRequest(hMutexSem, cMillies);
+}
+RT_EXPORT_SYMBOL(RTSemMutexRequestDebug);
+
+
+RTDECL(int) RTSemMutexRequestNoResume(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies)
+{
+ return rtSemMutexLinuxRequest(hMutexSem, cMillies, true /*fInterruptible*/);
+}
+RT_EXPORT_SYMBOL(RTSemMutexRequestNoResume);
+
+
+RTDECL(int) RTSemMutexRequestNoResumeDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
+{
+ RT_NOREF_PV(uId); RT_SRC_POS_NOREF();
+ return RTSemMutexRequestNoResume(hMutexSem, cMillies);
+}
+RT_EXPORT_SYMBOL(RTSemMutexRequestNoResumeDebug);
+
+
+RTDECL(int) RTSemMutexRelease(RTSEMMUTEX hMtx)
+{
+ PRTSEMMUTEXINTERNAL pThis = hMtx;
+ struct task_struct *pSelf = current;
+ unsigned long fSavedIrq;
+ int rc;
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ /*
+ * Validate.
+ */
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
+ Assert(pThis->cRefs >= 1);
+
+ /*
+ * Take the lock and release one recursion.
+ */
+ spin_lock_irqsave(&pThis->Spinlock, fSavedIrq);
+ if (pThis->pOwnerTask == pSelf)
+ {
+ Assert(pThis->cRecursions > 0);
+ if (--pThis->cRecursions == 0)
+ {
+ pThis->pOwnerTask = NULL;
+
+ /* anyone to wake up? */
+ if (!RTListIsEmpty(&pThis->WaiterList))
+ {
+ PRTSEMMUTEXLNXWAITER pWaiter = RTListGetFirst(&pThis->WaiterList, RTSEMMUTEXLNXWAITER, ListEntry);
+ pWaiter->enmReason = RTSEMMUTEXLNXWAITER_WAKEUP;
+ wake_up_process(pWaiter->pTask);
+ }
+ IPRT_DEBUG_SEMS_STATE(pThis, 'u');
+ }
+ rc = VINF_SUCCESS;
+ }
+ else
+ rc = VERR_NOT_OWNER;
+ spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq);
+
+ AssertRC(rc);
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTSemMutexRelease);
+
+
+RTDECL(bool) RTSemMutexIsOwned(RTSEMMUTEX hMutexSem)
+{
+ PRTSEMMUTEXINTERNAL pThis = hMutexSem;
+ unsigned long fSavedIrq;
+ bool fOwned;
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ /*
+ * Validate.
+ */
+ AssertPtrReturn(pThis, false);
+ AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), false);
+ Assert(pThis->cRefs >= 1);
+
+ /*
+ * Take the lock and release one recursion.
+ */
+ spin_lock_irqsave(&pThis->Spinlock, fSavedIrq);
+ fOwned = pThis->pOwnerTask != NULL;
+ spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq);
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return fOwned;
+
+}
+RT_EXPORT_SYMBOL(RTSemMutexIsOwned);
+
--- /dev/null
+/* $Id: spinlock-r0drv-linux.c $ */
+/** @file
+ * IPRT - Spinlocks, Ring-0 Driver, Linux.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "the-linux-kernel.h"
+#include "internal/iprt.h"
+#include <iprt/spinlock.h>
+
+#include <iprt/asm.h>
+#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
+# include <iprt/asm-amd64-x86.h>
+#endif
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/mem.h>
+#include <iprt/mp.h>
+#include <iprt/thread.h>
+#include "internal/magics.h"
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * Wrapper for the spinlock_t structure.
+ */
+typedef struct RTSPINLOCKINTERNAL
+{
+ /** Spinlock magic value (RTSPINLOCK_MAGIC). */
+ uint32_t volatile u32Magic;
+ /** The spinlock creation flags. */
+ uint32_t fFlags;
+ /** The saved interrupt flag. */
+ unsigned long volatile fIntSaved;
+ /** The linux spinlock structure. */
+ spinlock_t Spinlock;
+#ifdef RT_MORE_STRICT
+ /** The idAssertCpu variable before acquring the lock for asserting after
+ * releasing the spinlock. */
+ RTCPUID volatile idAssertCpu;
+ /** The CPU that owns the lock. */
+ RTCPUID volatile idCpuOwner;
+#endif
+} RTSPINLOCKINTERNAL, *PRTSPINLOCKINTERNAL;
+
+
+
+RTDECL(int) RTSpinlockCreate(PRTSPINLOCK pSpinlock, uint32_t fFlags, const char *pszName)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+ PRTSPINLOCKINTERNAL pThis;
+ AssertReturn(fFlags == RTSPINLOCK_FLAGS_INTERRUPT_SAFE || fFlags == RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, VERR_INVALID_PARAMETER);
+ RT_NOREF_PV(pszName);
+
+ /*
+ * Allocate.
+ */
+ Assert(sizeof(RTSPINLOCKINTERNAL) > sizeof(void *));
+ pThis = (PRTSPINLOCKINTERNAL)RTMemAlloc(sizeof(*pThis));
+ if (!pThis)
+ return VERR_NO_MEMORY;
+ /*
+ * Initialize and return.
+ */
+ pThis->u32Magic = RTSPINLOCK_MAGIC;
+ pThis->fFlags = fFlags;
+ pThis->fIntSaved = 0;
+#ifdef RT_MORE_STRICT
+ pThis->idCpuOwner = NIL_RTCPUID;
+ pThis->idAssertCpu = NIL_RTCPUID;
+#endif
+
+ spin_lock_init(&pThis->Spinlock);
+
+ *pSpinlock = pThis;
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTSpinlockCreate);
+
+
+RTDECL(int) RTSpinlockDestroy(RTSPINLOCK Spinlock)
+{
+ /*
+ * Validate input.
+ */
+ PRTSPINLOCKINTERNAL pThis = (PRTSPINLOCKINTERNAL)Spinlock;
+ if (!pThis)
+ return VERR_INVALID_PARAMETER;
+ if (pThis->u32Magic != RTSPINLOCK_MAGIC)
+ {
+ AssertMsgFailed(("Invalid spinlock %p magic=%#x\n", pThis, pThis->u32Magic));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ ASMAtomicIncU32(&pThis->u32Magic);
+ RTMemFree(pThis);
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTSpinlockDestroy);
+
+
+RTDECL(void) RTSpinlockAcquire(RTSPINLOCK Spinlock)
+{
+ PRTSPINLOCKINTERNAL pThis = (PRTSPINLOCKINTERNAL)Spinlock;
+ IPRT_LINUX_SAVE_EFL_AC();
+ RT_ASSERT_PREEMPT_CPUID_VAR();
+ AssertMsg(pThis && pThis->u32Magic == RTSPINLOCK_MAGIC,
+ ("pThis=%p u32Magic=%08x\n", pThis, pThis ? (int)pThis->u32Magic : 0));
+
+#ifdef CONFIG_PROVE_LOCKING
+ lockdep_off();
+#endif
+ if (pThis->fFlags & RTSPINLOCK_FLAGS_INTERRUPT_SAFE)
+ {
+ unsigned long fIntSaved;
+ spin_lock_irqsave(&pThis->Spinlock, fIntSaved);
+ pThis->fIntSaved = fIntSaved;
+ }
+ else
+ spin_lock(&pThis->Spinlock);
+#ifdef CONFIG_PROVE_LOCKING
+ lockdep_on();
+#endif
+
+ IPRT_LINUX_RESTORE_EFL_ONLY_AC();
+ RT_ASSERT_PREEMPT_CPUID_SPIN_ACQUIRED(pThis);
+}
+RT_EXPORT_SYMBOL(RTSpinlockAcquire);
+
+
+RTDECL(void) RTSpinlockRelease(RTSPINLOCK Spinlock)
+{
+ PRTSPINLOCKINTERNAL pThis = (PRTSPINLOCKINTERNAL)Spinlock;
+ IPRT_LINUX_SAVE_EFL_AC(); /* spin_unlock* may preempt and trash eflags.ac. */
+ RT_ASSERT_PREEMPT_CPUID_SPIN_RELEASE_VARS();
+ AssertMsg(pThis && pThis->u32Magic == RTSPINLOCK_MAGIC,
+ ("pThis=%p u32Magic=%08x\n", pThis, pThis ? (int)pThis->u32Magic : 0));
+ RT_ASSERT_PREEMPT_CPUID_SPIN_RELEASE(pThis);
+
+#ifdef CONFIG_PROVE_LOCKING
+ lockdep_off();
+#endif
+ if (pThis->fFlags & RTSPINLOCK_FLAGS_INTERRUPT_SAFE)
+ {
+ unsigned long fIntSaved = pThis->fIntSaved;
+ pThis->fIntSaved = 0;
+ spin_unlock_irqrestore(&pThis->Spinlock, fIntSaved);
+ }
+ else
+ spin_unlock(&pThis->Spinlock);
+#ifdef CONFIG_PROVE_LOCKING
+ lockdep_on();
+#endif
+
+ IPRT_LINUX_RESTORE_EFL_ONLY_AC();
+ RT_ASSERT_PREEMPT_CPUID();
+}
+RT_EXPORT_SYMBOL(RTSpinlockRelease);
+
--- /dev/null
+/* $Id: string.h $ */
+/** @file
+ * IPRT - wrapper for the linux kernel asm/string.h.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___string_h
+#define ___string_h
+
+#include <iprt/cdefs.h>
+
+RT_C_DECLS_BEGIN
+#ifndef bool /* Linux 2.6.19 C++ nightmare */
+#define bool bool_type
+#define true true_type
+#define false false_type
+#define _Bool int
+#define bool_type_r0drv_string_h__
+#endif
+#include <linux/types.h>
+#include <linux/string.h>
+#ifdef bool_type_r0drv_string_h__
+#undef bool
+#undef true
+#undef false
+#undef bool_type_r0drv_string_h__
+#endif
+char *strpbrk(const char *pszStr, const char *pszChars)
+#if defined(__THROW)
+ __THROW
+#endif
+ ;
+
+RT_C_DECLS_END
+
+#endif
+
--- /dev/null
+/* $Id: the-linux-kernel.h $ */
+/** @file
+ * IPRT - Include all necessary headers for the Linux kernel.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___the_linux_kernel_h
+#define ___the_linux_kernel_h
+
+/*
+ * Include iprt/types.h to install the bool wrappers.
+ * Then use the linux bool type for all the stuff include here.
+ */
+#include <iprt/types.h>
+#define bool linux_bool
+
+#if RT_GNUC_PREREQ(4, 6)
+# pragma GCC diagnostic push
+#endif
+#if RT_GNUC_PREREQ(4, 2)
+# pragma GCC diagnostic ignored "-Wunused-parameter"
+# if !defined(__cplusplus) && RT_GNUC_PREREQ(4, 3)
+# pragma GCC diagnostic ignored "-Wold-style-declaration" /* 2.6.18-411.0.0.0.1.el5/build/include/asm/apic.h:110: warning: 'inline' is not at beginning of declaration [-Wold-style-declaration] */
+# endif
+#endif
+
+#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
+
+/* We only support 2.4 and 2.6 series kernels */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
+# error We only support 2.4 and 2.6 series kernels
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
+# error We only support 2.4 and 2.6 series kernels
+#endif
+
+#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
+# define MODVERSIONS
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 71)
+# include <linux/modversions.h>
+# endif
+#endif
+#ifndef KBUILD_STR
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16)
+# define KBUILD_STR(s) s
+# else
+# define KBUILD_STR(s) #s
+# endif
+#endif
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
+# include <linux/kconfig.h> /* for macro IS_ENABLED */
+# endif
+#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+# include <linux/semaphore.h>
+#else /* older kernels */
+# include <asm/semaphore.h>
+#endif /* older kernels */
+#include <linux/module.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+# include <linux/moduleparam.h>
+#endif
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+# include <linux/namei.h>
+#endif
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/sched.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+# include <linux/sched/rt.h>
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+# include <linux/sched/signal.h>
+# include <linux/sched/types.h>
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 7)
+# include <linux/jiffies.h>
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 16)
+# include <linux/ktime.h>
+# include <linux/hrtimer.h>
+#endif
+#include <linux/wait.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 71)
+# include <linux/cpu.h>
+# include <linux/notifier.h>
+#endif
+/* For the basic additions module */
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/compiler.h>
+#ifndef HAVE_UNLOCKED_IOCTL /* linux/fs.h defines this */
+# include <linux/smp_lock.h>
+#endif
+/* For the shared folders module */
+#include <linux/vmalloc.h>
+#define wchar_t linux_wchar_t
+#include <linux/nls.h>
+#undef wchar_t
+#include <asm/mman.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/div64.h>
+
+/* For thread-context hooks. */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) && defined(CONFIG_PREEMPT_NOTIFIERS)
+# include <linux/preempt.h>
+#endif
+
+/* for workqueue / task queues. */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 41)
+# include <linux/workqueue.h>
+#else
+# include <linux/tqueue.h>
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+# include <linux/kthread.h>
+#endif
+
+/* for cr4_init_shadow() / cpu_tlbstate. */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 20, 0)
+# include <asm/tlbflush.h>
+#endif
+
+/* for set_pages_x() */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
+# include <asm/set_memory.h>
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)
+# include <asm/smap.h>
+#else
+static inline void clac(void) { }
+static inline void stac(void) { }
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
+# ifndef page_to_pfn
+# define page_to_pfn(page) ((page) - mem_map)
+# endif
+#endif
+
+#ifndef DEFINE_WAIT
+# define DEFINE_WAIT(name) DECLARE_WAITQUEUE(name, current)
+#endif
+
+#ifndef __GFP_NOWARN
+# define __GFP_NOWARN 0
+#endif
+
+/*
+ * 2.4 / early 2.6 compatibility wrappers
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 7)
+
+# ifndef MAX_JIFFY_OFFSET
+# define MAX_JIFFY_OFFSET ((~0UL >> 1)-1)
+# endif
+
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 29) || LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+
+DECLINLINE(unsigned int) jiffies_to_msecs(unsigned long cJiffies)
+{
+# if HZ <= 1000 && !(1000 % HZ)
+ return (1000 / HZ) * cJiffies;
+# elif HZ > 1000 && !(HZ % 1000)
+ return (cJiffies + (HZ / 1000) - 1) / (HZ / 1000);
+# else
+ return (cJiffies * 1000) / HZ;
+# endif
+}
+
+DECLINLINE(unsigned long) msecs_to_jiffies(unsigned int cMillies)
+{
+# if HZ > 1000
+ if (cMillies > jiffies_to_msecs(MAX_JIFFY_OFFSET))
+ return MAX_JIFFY_OFFSET;
+# endif
+# if HZ <= 1000 && !(1000 % HZ)
+ return (cMillies + (1000 / HZ) - 1) / (1000 / HZ);
+# elif HZ > 1000 && !(HZ % 1000)
+ return cMillies * (HZ / 1000);
+# else
+ return (cMillies * HZ + 999) / 1000;
+# endif
+}
+
+# endif /* < 2.4.29 || >= 2.6.0 */
+
+#endif /* < 2.6.7 */
+
+/*
+ * 2.4 compatibility wrappers
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
+
+# define prepare_to_wait(q, wait, state) \
+ do { \
+ add_wait_queue(q, wait); \
+ set_current_state(state); \
+ } while (0)
+
+# define after_wait(wait) \
+ do { \
+ list_del_init(&(wait)->task_list); \
+ } while (0)
+
+# define finish_wait(q, wait) \
+ do { \
+ set_current_state(TASK_RUNNING); \
+ remove_wait_queue(q, wait); \
+ } while (0)
+
+#else /* >= 2.6.0 */
+
+# define after_wait(wait) do {} while (0)
+
+#endif /* >= 2.6.0 */
+
+/** @def TICK_NSEC
+ * The time between ticks in nsec */
+#ifndef TICK_NSEC
+# define TICK_NSEC (1000000000UL / HZ)
+#endif
+
+/*
+ * This sucks soooo badly on x86! Why don't they export __PAGE_KERNEL_EXEC so PAGE_KERNEL_EXEC would be usable?
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 8) && defined(RT_ARCH_AMD64)
+# define MY_PAGE_KERNEL_EXEC PAGE_KERNEL_EXEC
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 8) && defined(PAGE_KERNEL_EXEC) && defined(CONFIG_X86_PAE)
+# ifdef __PAGE_KERNEL_EXEC
+ /* >= 2.6.27 */
+# define MY_PAGE_KERNEL_EXEC __pgprot(boot_cpu_has(X86_FEATURE_PGE) ? __PAGE_KERNEL_EXEC | _PAGE_GLOBAL : __PAGE_KERNEL_EXEC)
+# else
+# define MY_PAGE_KERNEL_EXEC __pgprot(boot_cpu_has(X86_FEATURE_PGE) ? _PAGE_KERNEL_EXEC | _PAGE_GLOBAL : _PAGE_KERNEL_EXEC)
+# endif
+#else
+# define MY_PAGE_KERNEL_EXEC PAGE_KERNEL
+#endif
+
+
+/*
+ * The redhat hack section.
+ * - The current hacks are for 2.4.21-15.EL only.
+ */
+#ifndef NO_REDHAT_HACKS
+/* accounting. */
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
+# ifdef VM_ACCOUNT
+# define USE_RHEL4_MUNMAP
+# endif
+# endif
+
+/* backported remap_page_range. */
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
+# include <asm/tlb.h>
+# ifdef tlb_vma /* probably not good enough... */
+# define HAVE_26_STYLE_REMAP_PAGE_RANGE 1
+# endif
+# endif
+
+# ifndef RT_ARCH_AMD64
+/* In 2.6.9-22.ELsmp we have to call change_page_attr() twice when changing
+ * the page attributes from PAGE_KERNEL to something else, because there appears
+ * to be a bug in one of the many patches that redhat applied.
+ * It should be safe to do this on less buggy linux kernels too. ;-)
+ */
+# define MY_CHANGE_PAGE_ATTR(pPages, cPages, prot) \
+ do { \
+ if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) \
+ change_page_attr(pPages, cPages, prot); \
+ change_page_attr(pPages, cPages, prot); \
+ } while (0)
+# endif /* !RT_ARCH_AMD64 */
+#endif /* !NO_REDHAT_HACKS */
+
+#ifndef MY_CHANGE_PAGE_ATTR
+# ifdef RT_ARCH_AMD64 /** @todo This is a cheap hack, but it'll get around that 'else BUG();' in __change_page_attr(). */
+# define MY_CHANGE_PAGE_ATTR(pPages, cPages, prot) \
+ do { \
+ change_page_attr(pPages, cPages, PAGE_KERNEL_NOCACHE); \
+ change_page_attr(pPages, cPages, prot); \
+ } while (0)
+# else
+# define MY_CHANGE_PAGE_ATTR(pPages, cPages, prot) change_page_attr(pPages, cPages, prot)
+# endif
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
+# define MY_SET_PAGES_EXEC(pPages, cPages) set_pages_x(pPages, cPages)
+# define MY_SET_PAGES_NOEXEC(pPages, cPages) set_pages_nx(pPages, cPages)
+#else
+# define MY_SET_PAGES_EXEC(pPages, cPages) \
+ do { \
+ if (pgprot_val(MY_PAGE_KERNEL_EXEC) != pgprot_val(PAGE_KERNEL)) \
+ MY_CHANGE_PAGE_ATTR(pPages, cPages, MY_PAGE_KERNEL_EXEC); \
+ } while (0)
+# define MY_SET_PAGES_NOEXEC(pPages, cPages) \
+ do { \
+ if (pgprot_val(MY_PAGE_KERNEL_EXEC) != pgprot_val(PAGE_KERNEL)) \
+ MY_CHANGE_PAGE_ATTR(pPages, cPages, PAGE_KERNEL); \
+ } while (0)
+#endif
+
+/** @def ONE_MSEC_IN_JIFFIES
+ * The number of jiffies that make up 1 millisecond. Must be at least 1! */
+#if HZ <= 1000
+# define ONE_MSEC_IN_JIFFIES 1
+#elif !(HZ % 1000)
+# define ONE_MSEC_IN_JIFFIES (HZ / 1000)
+#else
+# define ONE_MSEC_IN_JIFFIES ((HZ + 999) / 1000)
+# error "HZ is not a multiple of 1000, the GIP stuff won't work right!"
+#endif
+
+/*
+ * Stop using the linux bool type.
+ */
+#undef bool
+
+#if RT_GNUC_PREREQ(4, 6)
+# pragma GCC diagnostic pop
+#endif
+
+/*
+ * There are post-2.6.24 kernels (confusingly with unchanged version number)
+ * which eliminate macros which were marked as deprecated.
+ */
+#ifndef __attribute_used__
+#define __attribute_used__ __used
+#endif
+
+/**
+ * Hack for shortening pointers on linux so we can stuff more stuff into the
+ * task_struct::comm field. This is used by the semaphore code but put here
+ * because we don't have any better place atm. Don't use outside IPRT, please.
+ */
+#ifdef RT_ARCH_AMD64
+# define IPRT_DEBUG_SEMS_ADDRESS(addr) ( ((long)(addr) & (long)~UINT64_C(0xfffffff000000000)) )
+#else
+# define IPRT_DEBUG_SEMS_ADDRESS(addr) ( (long)(addr) )
+#endif
+
+/**
+ * Puts semaphore info into the task_struct::comm field if IPRT_DEBUG_SEMS is
+ * defined.
+ */
+#ifdef IPRT_DEBUG_SEMS
+# define IPRT_DEBUG_SEMS_STATE(pThis, chState) \
+ snprintf(current->comm, sizeof(current->comm), "%c%lx", (chState), IPRT_DEBUG_SEMS_ADDRESS(pThis));
+#else
+# define IPRT_DEBUG_SEMS_STATE(pThis, chState) do { } while (0)
+#endif
+
+/**
+ * Puts semaphore info into the task_struct::comm field if IPRT_DEBUG_SEMS is
+ * defined.
+ */
+#ifdef IPRT_DEBUG_SEMS
+# define IPRT_DEBUG_SEMS_STATE_RC(pThis, chState, rc) \
+ snprintf(current->comm, sizeof(current->comm), "%c%lx:%d", (chState), IPRT_DEBUG_SEMS_ADDRESS(pThis), rc);
+#else
+# define IPRT_DEBUG_SEMS_STATE_RC(pThis, chState, rc) do { } while (0)
+#endif
+
+/** @name Macros for preserving EFLAGS.AC on 3.19+/amd64 paranoid.
+ * The AMD 64 switch_to in macro in arch/x86/include/asm/switch_to.h stopped
+ * restoring flags.
+ * @{ */
+#if defined(CONFIG_X86_SMAP) || defined(RT_STRICT) || defined(IPRT_WITH_EFLAGS_AC_PRESERVING)
+# include <iprt/asm-amd64-x86.h>
+# define IPRT_X86_EFL_AC RT_BIT(18)
+# define IPRT_LINUX_SAVE_EFL_AC() RTCCUINTREG fSavedEfl = ASMGetFlags()
+# define IPRT_LINUX_RESTORE_EFL_AC() ASMSetFlags(fSavedEfl)
+# define IPRT_LINUX_RESTORE_EFL_ONLY_AC() ASMChangeFlags(~IPRT_X86_EFL_AC, fSavedEfl & IPRT_X86_EFL_AC)
+#else
+# define IPRT_LINUX_SAVE_EFL_AC() do { } while (0)
+# define IPRT_LINUX_RESTORE_EFL_AC() do { } while (0)
+# define IPRT_LINUX_RESTORE_EFL_ONLY_AC() do { } while (0)
+#endif
+/** @} */
+
+/*
+ * There are some conflicting defines in iprt/param.h, sort them out here.
+ */
+#ifndef ___iprt_param_h
+# undef PAGE_SIZE
+# undef PAGE_OFFSET_MASK
+# include <iprt/param.h>
+#endif
+
+/*
+ * Some global indicator macros.
+ */
+/** @def IPRT_LINUX_HAS_HRTIMER
+ * Whether the kernel support high resolution timers (Linux kernel versions
+ * 2.6.28 and later (hrtimer_add_expires_ns() & schedule_hrtimeout). */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
+# define IPRT_LINUX_HAS_HRTIMER
+#endif
+
+/*
+ * Workqueue stuff, see initterm-r0drv-linux.c.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 41)
+typedef struct work_struct RTR0LNXWORKQUEUEITEM;
+#else
+typedef struct tq_struct RTR0LNXWORKQUEUEITEM;
+#endif
+DECLHIDDEN(void) rtR0LnxWorkqueuePush(RTR0LNXWORKQUEUEITEM *pWork, void (*pfnWorker)(RTR0LNXWORKQUEUEITEM *));
+DECLHIDDEN(void) rtR0LnxWorkqueueFlush(void);
+
+
+#endif
--- /dev/null
+/* $Id: thread-r0drv-linux.c $ */
+/** @file
+ * IPRT - Threads, Ring-0 Driver, Linux.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "the-linux-kernel.h"
+#include "internal/iprt.h"
+#include <iprt/thread.h>
+
+#include <iprt/asm.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 28) || defined(CONFIG_X86_SMAP)
+# include <iprt/asm-amd64-x86.h>
+#endif
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/mp.h>
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+#ifndef CONFIG_PREEMPT
+/** Per-cpu preemption counters. */
+static int32_t volatile g_acPreemptDisabled[NR_CPUS];
+#endif
+
+
+RTDECL(RTNATIVETHREAD) RTThreadNativeSelf(void)
+{
+ return (RTNATIVETHREAD)current;
+}
+RT_EXPORT_SYMBOL(RTThreadNativeSelf);
+
+
+static int rtR0ThreadLnxSleepCommon(RTMSINTERVAL cMillies)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+ long cJiffies = msecs_to_jiffies(cMillies);
+ set_current_state(TASK_INTERRUPTIBLE);
+ cJiffies = schedule_timeout(cJiffies);
+ IPRT_LINUX_RESTORE_EFL_AC();
+ if (!cJiffies)
+ return VINF_SUCCESS;
+ return VERR_INTERRUPTED;
+}
+
+
+RTDECL(int) RTThreadSleep(RTMSINTERVAL cMillies)
+{
+ return rtR0ThreadLnxSleepCommon(cMillies);
+}
+RT_EXPORT_SYMBOL(RTThreadSleep);
+
+
+RTDECL(int) RTThreadSleepNoLog(RTMSINTERVAL cMillies)
+{
+ return rtR0ThreadLnxSleepCommon(cMillies);
+}
+RT_EXPORT_SYMBOL(RTThreadSleepNoLog);
+
+
+RTDECL(bool) RTThreadYield(void)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 20)
+ yield();
+#else
+ /** @todo r=ramshankar: Can we use cond_resched() instead? */
+ set_current_state(TASK_RUNNING);
+ sys_sched_yield();
+ schedule();
+#endif
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return true;
+}
+RT_EXPORT_SYMBOL(RTThreadYield);
+
+
+RTDECL(bool) RTThreadPreemptIsEnabled(RTTHREAD hThread)
+{
+#ifdef CONFIG_PREEMPT
+ Assert(hThread == NIL_RTTHREAD); RT_NOREF_PV(hThread);
+# ifdef preemptible
+ return preemptible();
+# else
+ return preempt_count() == 0 && !in_atomic() && !irqs_disabled();
+# endif
+#else
+ int32_t c;
+
+ Assert(hThread == NIL_RTTHREAD);
+ c = g_acPreemptDisabled[smp_processor_id()];
+ AssertMsg(c >= 0 && c < 32, ("%d\n", c));
+ if (c != 0)
+ return false;
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 32)
+ if (in_atomic())
+ return false;
+# endif
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 28)
+ if (irqs_disabled())
+ return false;
+# else
+ if (!ASMIntAreEnabled())
+ return false;
+# endif
+ return true;
+#endif
+}
+RT_EXPORT_SYMBOL(RTThreadPreemptIsEnabled);
+
+
+RTDECL(bool) RTThreadPreemptIsPending(RTTHREAD hThread)
+{
+ Assert(hThread == NIL_RTTHREAD); RT_NOREF_PV(hThread);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 4)
+ return !!test_tsk_thread_flag(current, TIF_NEED_RESCHED);
+
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 20)
+ return !!need_resched();
+
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 1, 110)
+ return current->need_resched != 0;
+
+#else
+ return need_resched != 0;
+#endif
+}
+RT_EXPORT_SYMBOL(RTThreadPreemptIsPending);
+
+
+RTDECL(bool) RTThreadPreemptIsPendingTrusty(void)
+{
+ /* yes, RTThreadPreemptIsPending is reliable. */
+ return true;
+}
+RT_EXPORT_SYMBOL(RTThreadPreemptIsPendingTrusty);
+
+
+RTDECL(bool) RTThreadPreemptIsPossible(void)
+{
+ /** @todo r=ramshankar: What about CONFIG_PREEMPT_VOLUNTARY? That can preempt
+ * too but does so in voluntarily in explicit preemption points. */
+#ifdef CONFIG_PREEMPT
+ return true; /* yes, kernel preemption is possible. */
+#else
+ return false; /* no kernel preemption */
+#endif
+}
+RT_EXPORT_SYMBOL(RTThreadPreemptIsPossible);
+
+
+RTDECL(void) RTThreadPreemptDisable(PRTTHREADPREEMPTSTATE pState)
+{
+#ifdef CONFIG_PREEMPT
+ AssertPtr(pState);
+ Assert(pState->u32Reserved == 0);
+ pState->u32Reserved = 42;
+ /* This ASSUMES that CONFIG_PREEMPT_COUNT is always defined with CONFIG_PREEMPT. */
+ preempt_disable();
+ RT_ASSERT_PREEMPT_CPUID_DISABLE(pState);
+
+#else /* !CONFIG_PREEMPT */
+ int32_t c;
+ AssertPtr(pState);
+ Assert(pState->u32Reserved == 0);
+
+ /* Do our own accounting. */
+ c = ASMAtomicIncS32(&g_acPreemptDisabled[smp_processor_id()]);
+ AssertMsg(c > 0 && c < 32, ("%d\n", c));
+ pState->u32Reserved = c;
+ RT_ASSERT_PREEMPT_CPUID_DISABLE(pState);
+#endif
+}
+RT_EXPORT_SYMBOL(RTThreadPreemptDisable);
+
+
+RTDECL(void) RTThreadPreemptRestore(PRTTHREADPREEMPTSTATE pState)
+{
+#ifdef CONFIG_PREEMPT
+ IPRT_LINUX_SAVE_EFL_AC(); /* paranoia */
+ AssertPtr(pState);
+ Assert(pState->u32Reserved == 42);
+ RT_ASSERT_PREEMPT_CPUID_RESTORE(pState);
+ preempt_enable();
+ IPRT_LINUX_RESTORE_EFL_ONLY_AC(); /* paranoia */
+
+#else
+ int32_t volatile *pc;
+ AssertPtr(pState);
+ AssertMsg(pState->u32Reserved > 0 && pState->u32Reserved < 32, ("%d\n", pState->u32Reserved));
+ RT_ASSERT_PREEMPT_CPUID_RESTORE(pState);
+
+ /* Do our own accounting. */
+ pc = &g_acPreemptDisabled[smp_processor_id()];
+ AssertMsg(pState->u32Reserved == (uint32_t)*pc, ("u32Reserved=%d *pc=%d \n", pState->u32Reserved, *pc));
+ ASMAtomicUoWriteS32(pc, pState->u32Reserved - 1);
+#endif
+ pState->u32Reserved = 0;
+}
+RT_EXPORT_SYMBOL(RTThreadPreemptRestore);
+
+
+RTDECL(bool) RTThreadIsInInterrupt(RTTHREAD hThread)
+{
+ Assert(hThread == NIL_RTTHREAD); NOREF(hThread);
+
+ return in_interrupt() != 0;
+}
+RT_EXPORT_SYMBOL(RTThreadIsInInterrupt);
+
--- /dev/null
+/* $Id: thread2-r0drv-linux.c $ */
+/** @file
+ * IPRT - Threads (Part 2), Ring-0 Driver, Linux.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "the-linux-kernel.h"
+#include "internal/iprt.h"
+
+#include <iprt/assert.h>
+#include <iprt/thread.h>
+#include <iprt/err.h>
+#include "internal/thread.h"
+
+
+RTDECL(RTTHREAD) RTThreadSelf(void)
+{
+ return rtThreadGetByNative((RTNATIVETHREAD)current);
+}
+
+
+DECLHIDDEN(int) rtThreadNativeInit(void)
+{
+ return VINF_SUCCESS;
+}
+
+
+DECLHIDDEN(int) rtThreadNativeSetPriority(PRTTHREADINT pThread, RTTHREADTYPE enmType)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
+ /* See comment near MAX_RT_PRIO in linux/sched.h for details on
+ sched_priority. */
+ int iSchedClass = SCHED_NORMAL;
+ struct sched_param Param = { .sched_priority = MAX_PRIO - 1 };
+ switch (enmType)
+ {
+ case RTTHREADTYPE_INFREQUENT_POLLER:
+ Param.sched_priority = MAX_RT_PRIO + 5;
+ break;
+
+ case RTTHREADTYPE_EMULATION:
+ Param.sched_priority = MAX_RT_PRIO + 4;
+ break;
+
+ case RTTHREADTYPE_DEFAULT:
+ Param.sched_priority = MAX_RT_PRIO + 3;
+ break;
+
+ case RTTHREADTYPE_MSG_PUMP:
+ Param.sched_priority = MAX_RT_PRIO + 2;
+ break;
+
+ case RTTHREADTYPE_IO:
+ iSchedClass = SCHED_FIFO;
+ Param.sched_priority = MAX_RT_PRIO - 1;
+ break;
+
+ case RTTHREADTYPE_TIMER:
+ iSchedClass = SCHED_FIFO;
+ Param.sched_priority = 1; /* not 0 just in case */
+ break;
+
+ default:
+ AssertMsgFailed(("enmType=%d\n", enmType));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ sched_setscheduler(current, iSchedClass, &Param);
+#else
+ RT_NOREF_PV(enmType);
+#endif
+ RT_NOREF_PV(pThread);
+
+ return VINF_SUCCESS;
+}
+
+
+DECLHIDDEN(int) rtThreadNativeAdopt(PRTTHREADINT pThread)
+{
+ RT_NOREF_PV(pThread);
+ return VERR_NOT_IMPLEMENTED;
+}
+
+
+DECLHIDDEN(void) rtThreadNativeWaitKludge(PRTTHREADINT pThread)
+{
+ /** @todo fix RTThreadWait/RTR0Term race on linux. */
+ RTThreadSleep(1); NOREF(pThread);
+}
+
+
+DECLHIDDEN(void) rtThreadNativeDestroy(PRTTHREADINT pThread)
+{
+ NOREF(pThread);
+}
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 4)
+/**
+ * Native kernel thread wrapper function.
+ *
+ * This will forward to rtThreadMain and do termination upon return.
+ *
+ * @param pvArg Pointer to the argument package.
+ */
+static int rtThreadNativeMain(void *pvArg)
+{
+ PRTTHREADINT pThread = (PRTTHREADINT)pvArg;
+
+ rtThreadMain(pThread, (RTNATIVETHREAD)current, &pThread->szName[0]);
+ return 0;
+}
+#endif
+
+
+DECLHIDDEN(int) rtThreadNativeCreate(PRTTHREADINT pThreadInt, PRTNATIVETHREAD pNativeThread)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 4)
+ struct task_struct *NativeThread;
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ RT_ASSERT_PREEMPTIBLE();
+
+ NativeThread = kthread_run(rtThreadNativeMain, pThreadInt, "iprt-%s", pThreadInt->szName);
+
+ if (!IS_ERR(NativeThread))
+ {
+ *pNativeThread = (RTNATIVETHREAD)NativeThread;
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+ }
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VERR_GENERAL_FAILURE;
+#else
+ return VERR_NOT_IMPLEMENTED;
+#endif
+}
+
--- /dev/null
+/* $Id: time-r0drv-linux.c $ */
+/** @file
+ * IPRT - Time, Ring-0 Driver, Linux.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP RTLOGGROUP_TIME
+#include "the-linux-kernel.h"
+#include "internal/iprt.h"
+#include <iprt/time.h>
+#include <iprt/asm.h>
+
+
+
+DECLINLINE(uint64_t) rtTimeGetSystemNanoTS(void)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 16) /* This must match timer-r0drv-linux.c! */
+ /*
+ * Use ktime_get_ts, this is also what clock_gettime(CLOCK_MONOTONIC,) is using.
+ */
+ uint64_t u64;
+ struct timespec Ts;
+ ktime_get_ts(&Ts);
+ u64 = Ts.tv_sec * RT_NS_1SEC_64 + Ts.tv_nsec;
+ return u64;
+
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 60)
+ /*
+ * Seems there is no way of getting to the exact source of
+ * sys_clock_gettime(CLOCK_MONOTONIC, &ts) here, I think. But
+ * 64-bit jiffies adjusted for the initial value should be pretty
+ * much the same I hope.
+ */
+ uint64_t u64 = get_jiffies_64();
+# ifdef INITIAL_JIFFIES
+ u64 += INITIAL_JIFFIES;
+# endif
+ u64 *= TICK_NSEC;
+ return u64;
+
+#else /* < 2.5.60 */
+# if BITS_PER_LONG >= 64
+ /*
+ * This is the same as above, except that there is no get_jiffies_64()
+ * here and we rely on long, and therefor jiffies, being 64-bit instead.
+ */
+ uint64_t u64 = jiffies;
+# ifdef INITIAL_JIFFIES
+ u64 += INITIAL_JIFFIES;
+# endif
+ u64 *= TICK_NSEC;
+ return u64;
+
+# else /* 32 bit jiffies */
+ /*
+ * We'll have to try track jiffy rollovers here or we'll be
+ * in trouble every time it flips.
+ *
+ * The high dword of the s_u64Last is the rollover count, the
+ * low dword is the previous jiffies. Updating is done by
+ * atomic compare & exchange of course.
+ */
+ static uint64_t volatile s_u64Last = 0;
+ uint64_t u64;
+
+ for (;;)
+ {
+ uint64_t u64NewLast;
+ int32_t iDelta;
+ uint32_t cRollovers;
+ uint32_t u32LastJiffies;
+
+ /* sample the values */
+ unsigned long ulNow = jiffies;
+ uint64_t u64Last = s_u64Last;
+ if (ulNow != jiffies)
+ continue; /* try again */
+# ifdef INITIAL_JIFFIES
+ ulNow += INITIAL_JIFFIES;
+# endif
+
+ u32LastJiffies = (uint32_t)u64Last;
+ cRollovers = u64Last >> 32;
+
+ /*
+ * Check for rollover and update the static last value.
+ *
+ * We have to make sure we update it successfully to rule out
+ * an underrun because of racing someone.
+ */
+ iDelta = ulNow - u32LastJiffies;
+ if (iDelta < 0)
+ {
+ cRollovers++;
+ u64NewLast = RT_MAKE_U64(ulNow, cRollovers);
+ if (!ASMAtomicCmpXchgU64(&s_u64Last, u64NewLast, u64Last))
+ continue; /* race, try again */
+ }
+ else
+ {
+ u64NewLast = RT_MAKE_U64(ulNow, cRollovers);
+ ASMAtomicCmpXchgU64(&s_u64Last, u64NewLast, u64Last);
+ }
+
+ /* calculate the return value */
+ u64 = ulNow;
+ u64 *= TICK_NSEC;
+ u64 += cRollovers * (_4G * TICK_NSEC);
+ break;
+ }
+
+ return u64;
+# endif /* 32 bit jiffies */
+#endif /* < 2.5.60 */
+}
+
+
+RTDECL(uint64_t) RTTimeNanoTS(void)
+{
+ return rtTimeGetSystemNanoTS();
+}
+RT_EXPORT_SYMBOL(RTTimeNanoTS);
+
+
+RTDECL(uint64_t) RTTimeMilliTS(void)
+{
+ return rtTimeGetSystemNanoTS() / RT_NS_1MS;
+}
+RT_EXPORT_SYMBOL(RTTimeMilliTS);
+
+
+RTDECL(uint64_t) RTTimeSystemNanoTS(void)
+{
+ return rtTimeGetSystemNanoTS();
+}
+RT_EXPORT_SYMBOL(RTTimeSystemNanoTS);
+
+
+RTDECL(uint64_t) RTTimeSystemMilliTS(void)
+{
+ return rtTimeGetSystemNanoTS() / RT_NS_1MS;
+}
+RT_EXPORT_SYMBOL(RTTimeSystemMilliTS);
+
+
+RTDECL(PRTTIMESPEC) RTTimeNow(PRTTIMESPEC pTime)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 16)
+ struct timespec Ts;
+ ktime_get_real_ts(&Ts);
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return RTTimeSpecSetTimespec(pTime, &Ts);
+
+#else /* < 2.6.16 */
+ struct timeval Tv;
+ do_gettimeofday(&Tv);
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return RTTimeSpecSetTimeval(pTime, &Tv);
+#endif
+}
+RT_EXPORT_SYMBOL(RTTimeNow);
+
--- /dev/null
+/* $Id: timer-r0drv-linux.c $ */
+/** @file
+ * IPRT - Timers, Ring-0 Driver, Linux.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "the-linux-kernel.h"
+#include "internal/iprt.h"
+
+#include <iprt/timer.h>
+#include <iprt/time.h>
+#include <iprt/mp.h>
+#include <iprt/cpuset.h>
+#include <iprt/spinlock.h>
+#include <iprt/err.h>
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/alloc.h>
+
+#include "internal/magics.h"
+
+/** @def RTTIMER_LINUX_WITH_HRTIMER
+ * Whether to use high resolution timers. */
+#if !defined(RTTIMER_LINUX_WITH_HRTIMER) \
+ && defined(IPRT_LINUX_HAS_HRTIMER)
+# define RTTIMER_LINUX_WITH_HRTIMER
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
+# define mod_timer_pinned mod_timer
+# define HRTIMER_MODE_ABS_PINNED HRTIMER_MODE_ABS
+#endif
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * Timer state machine.
+ *
+ * This is used to try handle the issues with MP events and
+ * timers that runs on all CPUs. It's relatively nasty :-/
+ */
+typedef enum RTTIMERLNXSTATE
+{
+ /** Stopped. */
+ RTTIMERLNXSTATE_STOPPED = 0,
+ /** Transient state; next ACTIVE. */
+ RTTIMERLNXSTATE_STARTING,
+ /** Transient state; next ACTIVE. (not really necessary) */
+ RTTIMERLNXSTATE_MP_STARTING,
+ /** Active. */
+ RTTIMERLNXSTATE_ACTIVE,
+ /** Active and in callback; next ACTIVE, STOPPED or CALLBACK_DESTROYING. */
+ RTTIMERLNXSTATE_CALLBACK,
+ /** Stopped while in the callback; next STOPPED. */
+ RTTIMERLNXSTATE_CB_STOPPING,
+ /** Restarted while in the callback; next ACTIVE, STOPPED, DESTROYING. */
+ RTTIMERLNXSTATE_CB_RESTARTING,
+ /** The callback shall destroy the timer; next STOPPED. */
+ RTTIMERLNXSTATE_CB_DESTROYING,
+ /** Transient state; next STOPPED. */
+ RTTIMERLNXSTATE_STOPPING,
+ /** Transient state; next STOPPED. */
+ RTTIMERLNXSTATE_MP_STOPPING,
+ /** The usual 32-bit hack. */
+ RTTIMERLNXSTATE_32BIT_HACK = 0x7fffffff
+} RTTIMERLNXSTATE;
+
+
+/**
+ * A Linux sub-timer.
+ */
+typedef struct RTTIMERLNXSUBTIMER
+{
+ /** Timer specific data. */
+ union
+ {
+#if defined(RTTIMER_LINUX_WITH_HRTIMER)
+ /** High resolution timer. */
+ struct
+ {
+ /** The linux timer structure. */
+ struct hrtimer LnxTimer;
+ } Hr;
+#endif
+ /** Standard timer. */
+ struct
+ {
+ /** The linux timer structure. */
+ struct timer_list LnxTimer;
+ /** The start of the current run (ns).
+ * This is used to calculate when the timer ought to fire the next time. */
+ uint64_t u64NextTS;
+ /** The u64NextTS in jiffies. */
+ unsigned long ulNextJiffies;
+ /** Set when starting or changing the timer so that u64StartTs
+ * and u64NextTS gets reinitialized (eliminating some jitter). */
+ bool volatile fFirstAfterChg;
+ } Std;
+ } u;
+ /** The current tick number. */
+ uint64_t iTick;
+ /** Restart the single shot timer at this specific time.
+ * Used when a single shot timer is restarted from the callback. */
+ uint64_t volatile uNsRestartAt;
+ /** Pointer to the parent timer. */
+ PRTTIMER pParent;
+ /** The current sub-timer state. */
+ RTTIMERLNXSTATE volatile enmState;
+} RTTIMERLNXSUBTIMER;
+/** Pointer to a linux sub-timer. */
+typedef RTTIMERLNXSUBTIMER *PRTTIMERLNXSUBTIMER;
+
+
+/**
+ * The internal representation of an Linux timer handle.
+ */
+typedef struct RTTIMER
+{
+ /** Magic.
+ * This is RTTIMER_MAGIC, but changes to something else before the timer
+ * is destroyed to indicate clearly that thread should exit. */
+ uint32_t volatile u32Magic;
+ /** Spinlock synchronizing the fSuspended and MP event handling.
+ * This is NIL_RTSPINLOCK if cCpus == 1. */
+ RTSPINLOCK hSpinlock;
+ /** Flag indicating that the timer is suspended. */
+ bool volatile fSuspended;
+ /** Whether the timer must run on one specific CPU or not. */
+ bool fSpecificCpu;
+#ifdef CONFIG_SMP
+ /** Whether the timer must run on all CPUs or not. */
+ bool fAllCpus;
+#endif /* else: All -> specific on non-SMP kernels */
+ /** Whether it is a high resolution timer or a standard one. */
+ bool fHighRes;
+ /** The id of the CPU it must run on if fSpecificCpu is set. */
+ RTCPUID idCpu;
+ /** The number of CPUs this timer should run on. */
+ RTCPUID cCpus;
+ /** Callback. */
+ PFNRTTIMER pfnTimer;
+ /** User argument. */
+ void *pvUser;
+ /** The timer interval. 0 if one-shot. */
+ uint64_t volatile u64NanoInterval;
+ /** This is set to the number of jiffies between ticks if the interval is
+ * an exact number of jiffies. (Standard timers only.) */
+ unsigned long volatile cJiffies;
+ /** The change interval spinlock for standard timers only. */
+ spinlock_t ChgIntLock;
+ /** Workqueue item for delayed destruction. */
+ RTR0LNXWORKQUEUEITEM DtorWorkqueueItem;
+ /** Sub-timers.
+ * Normally there is just one, but for RTTIMER_FLAGS_CPU_ALL this will contain
+ * an entry for all possible cpus. In that case the index will be the same as
+ * for the RTCpuSet. */
+ RTTIMERLNXSUBTIMER aSubTimers[1];
+} RTTIMER;
+
+
+/**
+ * A rtTimerLinuxStartOnCpu and rtTimerLinuxStartOnCpu argument package.
+ */
+typedef struct RTTIMERLINUXSTARTONCPUARGS
+{
+ /** The current time (RTTimeSystemNanoTS). */
+ uint64_t u64Now;
+ /** When to start firing (delta). */
+ uint64_t u64First;
+} RTTIMERLINUXSTARTONCPUARGS;
+/** Pointer to a rtTimerLinuxStartOnCpu argument package. */
+typedef RTTIMERLINUXSTARTONCPUARGS *PRTTIMERLINUXSTARTONCPUARGS;
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+#ifdef CONFIG_SMP
+static DECLCALLBACK(void) rtTimerLinuxMpEvent(RTMPEVENT enmEvent, RTCPUID idCpu, void *pvUser);
+#endif
+
+#if 0
+#define DEBUG_HACKING
+#include <iprt/string.h>
+#include <iprt/asm-amd64-x86.h>
+static void myLogBackdoorPrintf(const char *pszFormat, ...)
+{
+ char szTmp[256];
+ va_list args;
+ size_t cb;
+
+ cb = RTStrPrintf(szTmp, sizeof(szTmp) - 10, "%d: ", RTMpCpuId());
+ va_start(args, pszFormat);
+ cb += RTStrPrintfV(&szTmp[cb], sizeof(szTmp) - cb, pszFormat, args);
+ va_end(args);
+
+ ASMOutStrU8(0x504, (uint8_t *)&szTmp[0], cb);
+}
+# define RTAssertMsg1Weak(pszExpr, uLine, pszFile, pszFunction) \
+ myLogBackdoorPrintf("\n!!Guest Assertion failed!!\n%s(%d) %s\n%s\n", uLine, pszFile, pszFunction, (pszExpr))
+# define RTAssertMsg2Weak myLogBackdoorPrintf
+# define RTTIMERLNX_LOG(a) myLogBackdoorPrintf a
+#else
+# define RTTIMERLNX_LOG(a) do { } while (0)
+#endif
+
+/**
+ * Sets the state.
+ */
+DECLINLINE(void) rtTimerLnxSetState(RTTIMERLNXSTATE volatile *penmState, RTTIMERLNXSTATE enmNewState)
+{
+#ifdef DEBUG_HACKING
+ RTTIMERLNX_LOG(("set %d -> %d\n", *penmState, enmNewState));
+#endif
+ ASMAtomicWriteU32((uint32_t volatile *)penmState, enmNewState);
+}
+
+
+/**
+ * Sets the state if it has a certain value.
+ *
+ * @return true if xchg was done.
+ * @return false if xchg wasn't done.
+ */
+#ifdef DEBUG_HACKING
+#define rtTimerLnxCmpXchgState(penmState, enmNewState, enmCurState) rtTimerLnxCmpXchgStateDebug(penmState, enmNewState, enmCurState, __LINE__)
+static bool rtTimerLnxCmpXchgStateDebug(RTTIMERLNXSTATE volatile *penmState, RTTIMERLNXSTATE enmNewState,
+ RTTIMERLNXSTATE enmCurState, uint32_t uLine)
+{
+ RTTIMERLNXSTATE enmOldState = enmCurState;
+ bool fRc = ASMAtomicCmpXchgExU32((uint32_t volatile *)penmState, enmNewState, enmCurState, (uint32_t *)&enmOldState);
+ RTTIMERLNX_LOG(("cxg %d -> %d - %d at %u\n", enmOldState, enmNewState, fRc, uLine));
+ return fRc;
+}
+#else
+DECLINLINE(bool) rtTimerLnxCmpXchgState(RTTIMERLNXSTATE volatile *penmState, RTTIMERLNXSTATE enmNewState,
+ RTTIMERLNXSTATE enmCurState)
+{
+ return ASMAtomicCmpXchgU32((uint32_t volatile *)penmState, enmNewState, enmCurState);
+}
+#endif
+
+
+/**
+ * Gets the state.
+ */
+DECLINLINE(RTTIMERLNXSTATE) rtTimerLnxGetState(RTTIMERLNXSTATE volatile *penmState)
+{
+ return (RTTIMERLNXSTATE)ASMAtomicUoReadU32((uint32_t volatile *)penmState);
+}
+
+#ifdef RTTIMER_LINUX_WITH_HRTIMER
+
+/**
+ * Converts a nano second time stamp to ktime_t.
+ *
+ * ASSUMES RTTimeSystemNanoTS() is implemented using ktime_get_ts().
+ *
+ * @returns ktime_t.
+ * @param cNanoSecs Nanoseconds.
+ */
+DECLINLINE(ktime_t) rtTimerLnxNanoToKt(uint64_t cNanoSecs)
+{
+ /* With some luck the compiler optimizes the division out of this... (Bet it doesn't.) */
+ return ktime_set(cNanoSecs / 1000000000, cNanoSecs % 1000000000);
+}
+
+/**
+ * Converts ktime_t to a nano second time stamp.
+ *
+ * ASSUMES RTTimeSystemNanoTS() is implemented using ktime_get_ts().
+ *
+ * @returns nano second time stamp.
+ * @param Kt ktime_t.
+ */
+DECLINLINE(uint64_t) rtTimerLnxKtToNano(ktime_t Kt)
+{
+ return ktime_to_ns(Kt);
+}
+
+#endif /* RTTIMER_LINUX_WITH_HRTIMER */
+
+/**
+ * Converts a nano second interval to jiffies.
+ *
+ * @returns Jiffies.
+ * @param cNanoSecs Nanoseconds.
+ */
+DECLINLINE(unsigned long) rtTimerLnxNanoToJiffies(uint64_t cNanoSecs)
+{
+ /* this can be made even better... */
+ if (cNanoSecs > (uint64_t)TICK_NSEC * MAX_JIFFY_OFFSET)
+ return MAX_JIFFY_OFFSET;
+# if ARCH_BITS == 32
+ if (RT_LIKELY(cNanoSecs <= UINT32_MAX))
+ return ((uint32_t)cNanoSecs + (TICK_NSEC-1)) / TICK_NSEC;
+# endif
+ return (cNanoSecs + (TICK_NSEC-1)) / TICK_NSEC;
+}
+
+
+/**
+ * Starts a sub-timer (RTTimerStart).
+ *
+ * @param pSubTimer The sub-timer to start.
+ * @param u64Now The current timestamp (RTTimeSystemNanoTS()).
+ * @param u64First The interval from u64Now to the first time the timer should fire.
+ * @param fPinned true = timer pinned to a specific CPU,
+ * false = timer can migrate between CPUs
+ * @param fHighRes Whether the user requested a high resolution timer or not.
+ * @param enmOldState The old timer state.
+ */
+static void rtTimerLnxStartSubTimer(PRTTIMERLNXSUBTIMER pSubTimer, uint64_t u64Now, uint64_t u64First,
+ bool fPinned, bool fHighRes)
+{
+ /*
+ * Calc when it should start firing.
+ */
+ uint64_t u64NextTS = u64Now + u64First;
+ if (!fHighRes)
+ pSubTimer->u.Std.u64NextTS = u64NextTS;
+ RTTIMERLNX_LOG(("startsubtimer %p\n", pSubTimer->pParent));
+
+ pSubTimer->iTick = 0;
+
+#ifdef RTTIMER_LINUX_WITH_HRTIMER
+ if (fHighRes)
+ hrtimer_start(&pSubTimer->u.Hr.LnxTimer, rtTimerLnxNanoToKt(u64NextTS),
+ fPinned ? HRTIMER_MODE_ABS_PINNED : HRTIMER_MODE_ABS);
+ else
+#endif
+ {
+ unsigned long cJiffies = !u64First ? 0 : rtTimerLnxNanoToJiffies(u64First);
+ pSubTimer->u.Std.ulNextJiffies = jiffies + cJiffies;
+ pSubTimer->u.Std.fFirstAfterChg = true;
+#ifdef CONFIG_SMP
+ if (fPinned)
+ {
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)
+ mod_timer(&pSubTimer->u.Std.LnxTimer, pSubTimer->u.Std.ulNextJiffies);
+# else
+ mod_timer_pinned(&pSubTimer->u.Std.LnxTimer, pSubTimer->u.Std.ulNextJiffies);
+# endif
+ }
+ else
+#endif
+ mod_timer(&pSubTimer->u.Std.LnxTimer, pSubTimer->u.Std.ulNextJiffies);
+ }
+
+ /* Be a bit careful here since we could be racing the callback. */
+ if (!rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_ACTIVE, RTTIMERLNXSTATE_STARTING))
+ rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_ACTIVE, RTTIMERLNXSTATE_MP_STARTING);
+}
+
+
+/**
+ * Stops a sub-timer (RTTimerStart and rtTimerLinuxMpEvent()).
+ *
+ * The caller has already changed the state, so we will not be in a callback
+ * situation wrt to the calling thread.
+ *
+ * @param pSubTimer The sub-timer.
+ * @param fHighRes Whether the user requested a high resolution timer or not.
+ */
+static void rtTimerLnxStopSubTimer(PRTTIMERLNXSUBTIMER pSubTimer, bool fHighRes)
+{
+ RTTIMERLNX_LOG(("stopsubtimer %p %d\n", pSubTimer->pParent, fHighRes));
+#ifdef RTTIMER_LINUX_WITH_HRTIMER
+ if (fHighRes)
+ {
+ /* There is no equivalent to del_timer in the hrtimer API,
+ hrtimer_cancel() == del_timer_sync(). Just like the WARN_ON in
+ del_timer_sync() asserts, waiting for a timer callback to complete
+ is deadlock prone, so don't do it. */
+ int rc = hrtimer_try_to_cancel(&pSubTimer->u.Hr.LnxTimer);
+ if (rc < 0)
+ {
+ hrtimer_start(&pSubTimer->u.Hr.LnxTimer, ktime_set(KTIME_SEC_MAX, 0), HRTIMER_MODE_ABS);
+ hrtimer_try_to_cancel(&pSubTimer->u.Hr.LnxTimer);
+ }
+ }
+ else
+#endif
+ del_timer(&pSubTimer->u.Std.LnxTimer);
+
+ rtTimerLnxSetState(&pSubTimer->enmState, RTTIMERLNXSTATE_STOPPED);
+}
+
+
+/**
+ * Used by RTTimerDestroy and rtTimerLnxCallbackDestroy to do the actual work.
+ *
+ * @param pTimer The timer in question.
+ */
+static void rtTimerLnxDestroyIt(PRTTIMER pTimer)
+{
+ RTSPINLOCK hSpinlock = pTimer->hSpinlock;
+ RTCPUID iCpu;
+ Assert(pTimer->fSuspended);
+ RTTIMERLNX_LOG(("destroyit %p\n", pTimer));
+
+ /*
+ * Remove the MP notifications first because it'll reduce the risk of
+ * us overtaking any MP event that might theoretically be racing us here.
+ */
+#ifdef CONFIG_SMP
+ if ( pTimer->cCpus > 1
+ && hSpinlock != NIL_RTSPINLOCK)
+ {
+ int rc = RTMpNotificationDeregister(rtTimerLinuxMpEvent, pTimer);
+ AssertRC(rc);
+ }
+#endif /* CONFIG_SMP */
+
+ /*
+ * Invalidate the handle.
+ */
+ ASMAtomicWriteU32(&pTimer->u32Magic, ~RTTIMER_MAGIC);
+
+ /*
+ * Make sure all timers have stopped executing since we're stopping them in
+ * an asynchronous manner up in rtTimerLnxStopSubTimer.
+ */
+ iCpu = pTimer->cCpus;
+ while (iCpu-- > 0)
+ {
+#ifdef RTTIMER_LINUX_WITH_HRTIMER
+ if (pTimer->fHighRes)
+ hrtimer_cancel(&pTimer->aSubTimers[iCpu].u.Hr.LnxTimer);
+ else
+#endif
+ del_timer_sync(&pTimer->aSubTimers[iCpu].u.Std.LnxTimer);
+ }
+
+ /*
+ * Finally, free the resources.
+ */
+ RTMemFreeEx(pTimer, RT_OFFSETOF(RTTIMER, aSubTimers[pTimer->cCpus]));
+ if (hSpinlock != NIL_RTSPINLOCK)
+ RTSpinlockDestroy(hSpinlock);
+}
+
+
+/**
+ * Workqueue callback (no DECLCALLBACK!) for deferred destruction.
+ *
+ * @param pWork Pointer to the DtorWorkqueueItem member of our timer
+ * structure.
+ */
+static void rtTimerLnxDestroyDeferred(RTR0LNXWORKQUEUEITEM *pWork)
+{
+ PRTTIMER pTimer = RT_FROM_MEMBER(pWork, RTTIMER, DtorWorkqueueItem);
+ rtTimerLnxDestroyIt(pTimer);
+}
+
+
+/**
+ * Called when the timer was destroyed by the callback function.
+ *
+ * @param pTimer The timer.
+ * @param pSubTimer The sub-timer which we're handling, the state of this
+ * will be RTTIMERLNXSTATE_CALLBACK_DESTROYING.
+ */
+static void rtTimerLnxCallbackDestroy(PRTTIMER pTimer, PRTTIMERLNXSUBTIMER pSubTimer)
+{
+ /*
+ * If it's an omni timer, the last dude does the destroying.
+ */
+ if (pTimer->cCpus > 1)
+ {
+ uint32_t iCpu = pTimer->cCpus;
+ RTSpinlockAcquire(pTimer->hSpinlock);
+
+ Assert(pSubTimer->enmState == RTTIMERLNXSTATE_CB_DESTROYING);
+ rtTimerLnxSetState(&pSubTimer->enmState, RTTIMERLNXSTATE_STOPPED);
+
+ while (iCpu-- > 0)
+ if (rtTimerLnxGetState(&pTimer->aSubTimers[iCpu].enmState) != RTTIMERLNXSTATE_STOPPED)
+ {
+ RTSpinlockRelease(pTimer->hSpinlock);
+ return;
+ }
+
+ RTSpinlockRelease(pTimer->hSpinlock);
+ }
+
+ /*
+ * Destroying a timer from the callback is unsafe since the callout code
+ * might be touching the timer structure upon return (hrtimer does!). So,
+ * we have to defer the actual destruction to the IRPT workqueue.
+ */
+ rtR0LnxWorkqueuePush(&pTimer->DtorWorkqueueItem, rtTimerLnxDestroyDeferred);
+}
+
+
+#ifdef CONFIG_SMP
+/**
+ * Deal with a sub-timer that has migrated.
+ *
+ * @param pTimer The timer.
+ * @param pSubTimer The sub-timer.
+ */
+static void rtTimerLnxCallbackHandleMigration(PRTTIMER pTimer, PRTTIMERLNXSUBTIMER pSubTimer)
+{
+ RTTIMERLNXSTATE enmState;
+ if (pTimer->cCpus > 1)
+ RTSpinlockAcquire(pTimer->hSpinlock);
+
+ do
+ {
+ enmState = rtTimerLnxGetState(&pSubTimer->enmState);
+ switch (enmState)
+ {
+ case RTTIMERLNXSTATE_STOPPING:
+ case RTTIMERLNXSTATE_MP_STOPPING:
+ enmState = RTTIMERLNXSTATE_STOPPED;
+ case RTTIMERLNXSTATE_STOPPED:
+ break;
+
+ default:
+ AssertMsgFailed(("%d\n", enmState));
+ case RTTIMERLNXSTATE_STARTING:
+ case RTTIMERLNXSTATE_MP_STARTING:
+ case RTTIMERLNXSTATE_ACTIVE:
+ case RTTIMERLNXSTATE_CALLBACK:
+ case RTTIMERLNXSTATE_CB_STOPPING:
+ case RTTIMERLNXSTATE_CB_RESTARTING:
+ if (rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_STOPPED, enmState))
+ enmState = RTTIMERLNXSTATE_STOPPED;
+ break;
+
+ case RTTIMERLNXSTATE_CB_DESTROYING:
+ {
+ if (pTimer->cCpus > 1)
+ RTSpinlockRelease(pTimer->hSpinlock);
+
+ rtTimerLnxCallbackDestroy(pTimer, pSubTimer);
+ return;
+ }
+ }
+ } while (enmState != RTTIMERLNXSTATE_STOPPED);
+
+ if (pTimer->cCpus > 1)
+ RTSpinlockRelease(pTimer->hSpinlock);
+}
+#endif /* CONFIG_SMP */
+
+
+/**
+ * The slow path of rtTimerLnxChangeToCallbackState.
+ *
+ * @returns true if changed successfully, false if not.
+ * @param pSubTimer The sub-timer.
+ */
+static bool rtTimerLnxChangeToCallbackStateSlow(PRTTIMERLNXSUBTIMER pSubTimer)
+{
+ for (;;)
+ {
+ RTTIMERLNXSTATE enmState = rtTimerLnxGetState(&pSubTimer->enmState);
+ switch (enmState)
+ {
+ case RTTIMERLNXSTATE_ACTIVE:
+ case RTTIMERLNXSTATE_STARTING:
+ case RTTIMERLNXSTATE_MP_STARTING:
+ if (rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_CALLBACK, enmState))
+ return true;
+ break;
+
+ case RTTIMERLNXSTATE_CALLBACK:
+ case RTTIMERLNXSTATE_CB_STOPPING:
+ case RTTIMERLNXSTATE_CB_RESTARTING:
+ case RTTIMERLNXSTATE_CB_DESTROYING:
+ AssertMsgFailed(("%d\n", enmState));
+ default:
+ return false;
+ }
+ ASMNopPause();
+ }
+}
+
+
+/**
+ * Tries to change the sub-timer state to 'callback'.
+ *
+ * @returns true if changed successfully, false if not.
+ * @param pSubTimer The sub-timer.
+ */
+DECLINLINE(bool) rtTimerLnxChangeToCallbackState(PRTTIMERLNXSUBTIMER pSubTimer)
+{
+ if (RT_LIKELY(rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_CALLBACK, RTTIMERLNXSTATE_ACTIVE)))
+ return true;
+ return rtTimerLnxChangeToCallbackStateSlow(pSubTimer);
+}
+
+
+#ifdef RTTIMER_LINUX_WITH_HRTIMER
+/**
+ * Timer callback function for high resolution timers.
+ *
+ * @returns HRTIMER_NORESTART or HRTIMER_RESTART depending on whether it's a
+ * one-shot or interval timer.
+ * @param pHrTimer Pointer to the sub-timer structure.
+ */
+static enum hrtimer_restart rtTimerLinuxHrCallback(struct hrtimer *pHrTimer)
+{
+ PRTTIMERLNXSUBTIMER pSubTimer = RT_FROM_MEMBER(pHrTimer, RTTIMERLNXSUBTIMER, u.Hr.LnxTimer);
+ PRTTIMER pTimer = pSubTimer->pParent;
+
+
+ RTTIMERLNX_LOG(("hrcallback %p\n", pTimer));
+ if (RT_UNLIKELY(!rtTimerLnxChangeToCallbackState(pSubTimer)))
+ return HRTIMER_NORESTART;
+
+#ifdef CONFIG_SMP
+ /*
+ * Check for unwanted migration.
+ */
+ if (pTimer->fAllCpus || pTimer->fSpecificCpu)
+ {
+ RTCPUID idCpu = RTMpCpuId();
+ if (RT_UNLIKELY( pTimer->fAllCpus
+ ? (RTCPUID)(pSubTimer - &pTimer->aSubTimers[0]) != idCpu
+ : pTimer->idCpu != idCpu))
+ {
+ rtTimerLnxCallbackHandleMigration(pTimer, pSubTimer);
+ return HRTIMER_NORESTART;
+ }
+ }
+#endif
+
+ if (pTimer->u64NanoInterval)
+ {
+ /*
+ * Periodic timer, run it and update the native timer afterwards so
+ * we can handle RTTimerStop and RTTimerChangeInterval from the
+ * callback as well as a racing control thread.
+ */
+ pTimer->pfnTimer(pTimer, pTimer->pvUser, ++pSubTimer->iTick);
+ hrtimer_add_expires_ns(&pSubTimer->u.Hr.LnxTimer, ASMAtomicReadU64(&pTimer->u64NanoInterval));
+ if (RT_LIKELY(rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_ACTIVE, RTTIMERLNXSTATE_CALLBACK)))
+ return HRTIMER_RESTART;
+ }
+ else
+ {
+ /*
+ * One shot timer (no omni), stop it before dispatching it.
+ * Allow RTTimerStart as well as RTTimerDestroy to be called from
+ * the callback.
+ */
+ ASMAtomicWriteBool(&pTimer->fSuspended, true);
+ pTimer->pfnTimer(pTimer, pTimer->pvUser, ++pSubTimer->iTick);
+ if (RT_LIKELY(rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_STOPPED, RTTIMERLNXSTATE_CALLBACK)))
+ return HRTIMER_NORESTART;
+ }
+
+ /*
+ * Some state change occurred while we were in the callback routine.
+ */
+ for (;;)
+ {
+ RTTIMERLNXSTATE enmState = rtTimerLnxGetState(&pSubTimer->enmState);
+ switch (enmState)
+ {
+ case RTTIMERLNXSTATE_CB_DESTROYING:
+ rtTimerLnxCallbackDestroy(pTimer, pSubTimer);
+ return HRTIMER_NORESTART;
+
+ case RTTIMERLNXSTATE_CB_STOPPING:
+ if (rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_STOPPED, RTTIMERLNXSTATE_CB_STOPPING))
+ return HRTIMER_NORESTART;
+ break;
+
+ case RTTIMERLNXSTATE_CB_RESTARTING:
+ if (rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_ACTIVE, RTTIMERLNXSTATE_CB_RESTARTING))
+ {
+ pSubTimer->iTick = 0;
+ hrtimer_set_expires(&pSubTimer->u.Hr.LnxTimer, rtTimerLnxNanoToKt(pSubTimer->uNsRestartAt));
+ return HRTIMER_RESTART;
+ }
+ break;
+
+ default:
+ AssertMsgFailed(("%d\n", enmState));
+ return HRTIMER_NORESTART;
+ }
+ ASMNopPause();
+ }
+}
+#endif /* RTTIMER_LINUX_WITH_HRTIMER */
+
+
+/**
+ * Timer callback function for standard timers.
+ *
+ * @param ulUser Address of the sub-timer structure.
+ */
+static void rtTimerLinuxStdCallback(unsigned long ulUser)
+{
+ PRTTIMERLNXSUBTIMER pSubTimer = (PRTTIMERLNXSUBTIMER)ulUser;
+ PRTTIMER pTimer = pSubTimer->pParent;
+
+ RTTIMERLNX_LOG(("stdcallback %p\n", pTimer));
+ if (RT_UNLIKELY(!rtTimerLnxChangeToCallbackState(pSubTimer)))
+ return;
+
+#ifdef CONFIG_SMP
+ /*
+ * Check for unwanted migration.
+ */
+ if (pTimer->fAllCpus || pTimer->fSpecificCpu)
+ {
+ RTCPUID idCpu = RTMpCpuId();
+ if (RT_UNLIKELY( pTimer->fAllCpus
+ ? (RTCPUID)(pSubTimer - &pTimer->aSubTimers[0]) != idCpu
+ : pTimer->idCpu != idCpu))
+ {
+ rtTimerLnxCallbackHandleMigration(pTimer, pSubTimer);
+ return;
+ }
+ }
+#endif
+
+ if (pTimer->u64NanoInterval)
+ {
+ /*
+ * Interval timer, calculate the next timeout.
+ *
+ * The first time around, we'll re-adjust the u.Std.u64NextTS to
+ * try prevent some jittering if we were started at a bad time.
+ */
+ const uint64_t iTick = ++pSubTimer->iTick;
+ uint64_t u64NanoInterval;
+ unsigned long cJiffies;
+ unsigned long flFlags;
+
+ spin_lock_irqsave(&pTimer->ChgIntLock, flFlags);
+ u64NanoInterval = pTimer->u64NanoInterval;
+ cJiffies = pTimer->cJiffies;
+ if (RT_UNLIKELY(pSubTimer->u.Std.fFirstAfterChg))
+ {
+ pSubTimer->u.Std.fFirstAfterChg = false;
+ pSubTimer->u.Std.u64NextTS = RTTimeSystemNanoTS();
+ pSubTimer->u.Std.ulNextJiffies = jiffies;
+ }
+ spin_unlock_irqrestore(&pTimer->ChgIntLock, flFlags);
+
+ pSubTimer->u.Std.u64NextTS += u64NanoInterval;
+ if (cJiffies)
+ {
+ pSubTimer->u.Std.ulNextJiffies += cJiffies;
+ /* Prevent overflows when the jiffies counter wraps around.
+ * Special thanks to Ken Preslan for helping debugging! */
+ while (time_before(pSubTimer->u.Std.ulNextJiffies, jiffies))
+ {
+ pSubTimer->u.Std.ulNextJiffies += cJiffies;
+ pSubTimer->u.Std.u64NextTS += u64NanoInterval;
+ }
+ }
+ else
+ {
+ const uint64_t u64NanoTS = RTTimeSystemNanoTS();
+ while (pSubTimer->u.Std.u64NextTS < u64NanoTS)
+ pSubTimer->u.Std.u64NextTS += u64NanoInterval;
+ pSubTimer->u.Std.ulNextJiffies = jiffies + rtTimerLnxNanoToJiffies(pSubTimer->u.Std.u64NextTS - u64NanoTS);
+ }
+
+ /*
+ * Run the timer and re-arm it unless the state changed .
+ * .
+ * We must re-arm it afterwards as we're not in a position to undo this .
+ * operation if for instance someone stopped or destroyed us while we .
+ * were in the callback. (Linux takes care of any races here.)
+ */
+ pTimer->pfnTimer(pTimer, pTimer->pvUser, iTick);
+ if (RT_LIKELY(rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_ACTIVE, RTTIMERLNXSTATE_CALLBACK)))
+ {
+#ifdef CONFIG_SMP
+ if (pTimer->fSpecificCpu || pTimer->fAllCpus)
+ {
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)
+ mod_timer(&pSubTimer->u.Std.LnxTimer, pSubTimer->u.Std.ulNextJiffies);
+# else
+ mod_timer_pinned(&pSubTimer->u.Std.LnxTimer, pSubTimer->u.Std.ulNextJiffies);
+# endif
+ }
+ else
+#endif
+ mod_timer(&pSubTimer->u.Std.LnxTimer, pSubTimer->u.Std.ulNextJiffies);
+ return;
+ }
+ }
+ else
+ {
+ /*
+ * One shot timer, stop it before dispatching it.
+ * Allow RTTimerStart as well as RTTimerDestroy to be called from
+ * the callback.
+ */
+ ASMAtomicWriteBool(&pTimer->fSuspended, true);
+ pTimer->pfnTimer(pTimer, pTimer->pvUser, ++pSubTimer->iTick);
+ if (RT_LIKELY(rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_STOPPED, RTTIMERLNXSTATE_CALLBACK)))
+ return;
+ }
+
+ /*
+ * Some state change occurred while we were in the callback routine.
+ */
+ for (;;)
+ {
+ RTTIMERLNXSTATE enmState = rtTimerLnxGetState(&pSubTimer->enmState);
+ switch (enmState)
+ {
+ case RTTIMERLNXSTATE_CB_DESTROYING:
+ rtTimerLnxCallbackDestroy(pTimer, pSubTimer);
+ return;
+
+ case RTTIMERLNXSTATE_CB_STOPPING:
+ if (rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_STOPPED, RTTIMERLNXSTATE_CB_STOPPING))
+ return;
+ break;
+
+ case RTTIMERLNXSTATE_CB_RESTARTING:
+ if (rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_ACTIVE, RTTIMERLNXSTATE_CB_RESTARTING))
+ {
+ uint64_t u64NanoTS;
+ uint64_t u64NextTS;
+ unsigned long flFlags;
+
+ spin_lock_irqsave(&pTimer->ChgIntLock, flFlags);
+ u64NextTS = pSubTimer->uNsRestartAt;
+ u64NanoTS = RTTimeSystemNanoTS();
+ pSubTimer->iTick = 0;
+ pSubTimer->u.Std.u64NextTS = u64NextTS;
+ pSubTimer->u.Std.fFirstAfterChg = true;
+ pSubTimer->u.Std.ulNextJiffies = u64NextTS > u64NanoTS
+ ? jiffies + rtTimerLnxNanoToJiffies(u64NextTS - u64NanoTS)
+ : jiffies;
+ spin_unlock_irqrestore(&pTimer->ChgIntLock, flFlags);
+
+#ifdef CONFIG_SMP
+ if (pTimer->fSpecificCpu || pTimer->fAllCpus)
+ {
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)
+ mod_timer(&pSubTimer->u.Std.LnxTimer, pSubTimer->u.Std.ulNextJiffies);
+# else
+ mod_timer_pinned(&pSubTimer->u.Std.LnxTimer, pSubTimer->u.Std.ulNextJiffies);
+# endif
+ }
+ else
+#endif
+ mod_timer(&pSubTimer->u.Std.LnxTimer, pSubTimer->u.Std.ulNextJiffies);
+ return;
+ }
+ break;
+
+ default:
+ AssertMsgFailed(("%d\n", enmState));
+ return;
+ }
+ ASMNopPause();
+ }
+}
+
+
+#ifdef CONFIG_SMP
+
+/**
+ * Per-cpu callback function (RTMpOnAll/RTMpOnSpecific).
+ *
+ * @param idCpu The current CPU.
+ * @param pvUser1 Pointer to the timer.
+ * @param pvUser2 Pointer to the argument structure.
+ */
+static DECLCALLBACK(void) rtTimerLnxStartAllOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
+{
+ PRTTIMERLINUXSTARTONCPUARGS pArgs = (PRTTIMERLINUXSTARTONCPUARGS)pvUser2;
+ PRTTIMER pTimer = (PRTTIMER)pvUser1;
+ Assert(idCpu < pTimer->cCpus);
+ rtTimerLnxStartSubTimer(&pTimer->aSubTimers[idCpu], pArgs->u64Now, pArgs->u64First, true /*fPinned*/, pTimer->fHighRes);
+}
+
+
+/**
+ * Worker for RTTimerStart() that takes care of the ugly bits.
+ *
+ * @returns RTTimerStart() return value.
+ * @param pTimer The timer.
+ * @param pArgs The argument structure.
+ */
+static int rtTimerLnxOmniStart(PRTTIMER pTimer, PRTTIMERLINUXSTARTONCPUARGS pArgs)
+{
+ RTCPUID iCpu;
+ RTCPUSET OnlineSet;
+ RTCPUSET OnlineSet2;
+ int rc2;
+
+ /*
+ * Prepare all the sub-timers for the startup and then flag the timer
+ * as a whole as non-suspended, make sure we get them all before
+ * clearing fSuspended as the MP handler will be waiting on this
+ * should something happen while we're looping.
+ */
+ RTSpinlockAcquire(pTimer->hSpinlock);
+
+ /* Just make it a omni timer restriction that no stop/start races are allowed. */
+ for (iCpu = 0; iCpu < pTimer->cCpus; iCpu++)
+ if (rtTimerLnxGetState(&pTimer->aSubTimers[iCpu].enmState) != RTTIMERLNXSTATE_STOPPED)
+ {
+ RTSpinlockRelease(pTimer->hSpinlock);
+ return VERR_TIMER_BUSY;
+ }
+
+ do
+ {
+ RTMpGetOnlineSet(&OnlineSet);
+ for (iCpu = 0; iCpu < pTimer->cCpus; iCpu++)
+ {
+ Assert(pTimer->aSubTimers[iCpu].enmState != RTTIMERLNXSTATE_MP_STOPPING);
+ rtTimerLnxSetState(&pTimer->aSubTimers[iCpu].enmState,
+ RTCpuSetIsMember(&OnlineSet, iCpu)
+ ? RTTIMERLNXSTATE_STARTING
+ : RTTIMERLNXSTATE_STOPPED);
+ }
+ } while (!RTCpuSetIsEqual(&OnlineSet, RTMpGetOnlineSet(&OnlineSet2)));
+
+ ASMAtomicWriteBool(&pTimer->fSuspended, false);
+
+ RTSpinlockRelease(pTimer->hSpinlock);
+
+ /*
+ * Start them (can't find any exported function that allows me to
+ * do this without the cross calls).
+ */
+ pArgs->u64Now = RTTimeSystemNanoTS();
+ rc2 = RTMpOnAll(rtTimerLnxStartAllOnCpu, pTimer, pArgs);
+ AssertRC(rc2); /* screw this if it fails. */
+
+ /*
+ * Reset the sub-timers who didn't start up (ALL CPUs case).
+ */
+ RTSpinlockAcquire(pTimer->hSpinlock);
+
+ for (iCpu = 0; iCpu < pTimer->cCpus; iCpu++)
+ if (rtTimerLnxCmpXchgState(&pTimer->aSubTimers[iCpu].enmState, RTTIMERLNXSTATE_STOPPED, RTTIMERLNXSTATE_STARTING))
+ {
+ /** @todo very odd case for a rainy day. Cpus that temporarily went offline while
+ * we were between calls needs to nudged as the MP handler will ignore events for
+ * them because of the STARTING state. This is an extremely unlikely case - not that
+ * that means anything in my experience... ;-) */
+ RTTIMERLNX_LOG(("what!? iCpu=%u -> didn't start\n", iCpu));
+ }
+
+ RTSpinlockRelease(pTimer->hSpinlock);
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Worker for RTTimerStop() that takes care of the ugly SMP bits.
+ *
+ * @returns true if there was any active callbacks, false if not.
+ * @param pTimer The timer (valid).
+ * @param fForDestroy Whether this is for RTTimerDestroy or not.
+ */
+static bool rtTimerLnxOmniStop(PRTTIMER pTimer, bool fForDestroy)
+{
+ bool fActiveCallbacks = false;
+ RTCPUID iCpu;
+ RTTIMERLNXSTATE enmState;
+
+
+ /*
+ * Mark the timer as suspended and flag all timers as stopping, except
+ * for those being stopped by an MP event.
+ */
+ RTSpinlockAcquire(pTimer->hSpinlock);
+
+ ASMAtomicWriteBool(&pTimer->fSuspended, true);
+ for (iCpu = 0; iCpu < pTimer->cCpus; iCpu++)
+ {
+ for (;;)
+ {
+ enmState = rtTimerLnxGetState(&pTimer->aSubTimers[iCpu].enmState);
+ if ( enmState == RTTIMERLNXSTATE_STOPPED
+ || enmState == RTTIMERLNXSTATE_MP_STOPPING)
+ break;
+ if ( enmState == RTTIMERLNXSTATE_CALLBACK
+ || enmState == RTTIMERLNXSTATE_CB_STOPPING
+ || enmState == RTTIMERLNXSTATE_CB_RESTARTING)
+ {
+ Assert(enmState != RTTIMERLNXSTATE_CB_STOPPING || fForDestroy);
+ if (rtTimerLnxCmpXchgState(&pTimer->aSubTimers[iCpu].enmState,
+ !fForDestroy ? RTTIMERLNXSTATE_CB_STOPPING : RTTIMERLNXSTATE_CB_DESTROYING,
+ enmState))
+ {
+ fActiveCallbacks = true;
+ break;
+ }
+ }
+ else
+ {
+ Assert(enmState == RTTIMERLNXSTATE_ACTIVE);
+ if (rtTimerLnxCmpXchgState(&pTimer->aSubTimers[iCpu].enmState, RTTIMERLNXSTATE_STOPPING, enmState))
+ break;
+ }
+ ASMNopPause();
+ }
+ }
+
+ RTSpinlockRelease(pTimer->hSpinlock);
+
+ /*
+ * Do the actual stopping. Fortunately, this doesn't require any IPIs.
+ * Unfortunately it cannot be done synchronously.
+ */
+ for (iCpu = 0; iCpu < pTimer->cCpus; iCpu++)
+ if (rtTimerLnxGetState(&pTimer->aSubTimers[iCpu].enmState) == RTTIMERLNXSTATE_STOPPING)
+ rtTimerLnxStopSubTimer(&pTimer->aSubTimers[iCpu], pTimer->fHighRes);
+
+ return fActiveCallbacks;
+}
+
+
+/**
+ * Per-cpu callback function (RTMpOnSpecific) used by rtTimerLinuxMpEvent()
+ * to start a sub-timer on a cpu that just have come online.
+ *
+ * @param idCpu The current CPU.
+ * @param pvUser1 Pointer to the timer.
+ * @param pvUser2 Pointer to the argument structure.
+ */
+static DECLCALLBACK(void) rtTimerLinuxMpStartOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
+{
+ PRTTIMERLINUXSTARTONCPUARGS pArgs = (PRTTIMERLINUXSTARTONCPUARGS)pvUser2;
+ PRTTIMER pTimer = (PRTTIMER)pvUser1;
+ RTSPINLOCK hSpinlock;
+ Assert(idCpu < pTimer->cCpus);
+
+ /*
+ * We have to be kind of careful here as we might be racing RTTimerStop
+ * (and/or RTTimerDestroy, thus the paranoia.
+ */
+ hSpinlock = pTimer->hSpinlock;
+ if ( hSpinlock != NIL_RTSPINLOCK
+ && pTimer->u32Magic == RTTIMER_MAGIC)
+ {
+ RTSpinlockAcquire(hSpinlock);
+
+ if ( !ASMAtomicUoReadBool(&pTimer->fSuspended)
+ && pTimer->u32Magic == RTTIMER_MAGIC)
+ {
+ /* We're sane and the timer is not suspended yet. */
+ PRTTIMERLNXSUBTIMER pSubTimer = &pTimer->aSubTimers[idCpu];
+ if (rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_MP_STARTING, RTTIMERLNXSTATE_STOPPED))
+ rtTimerLnxStartSubTimer(pSubTimer, pArgs->u64Now, pArgs->u64First, true /*fPinned*/, pTimer->fHighRes);
+ }
+
+ RTSpinlockRelease(hSpinlock);
+ }
+}
+
+
+/**
+ * MP event notification callback.
+ *
+ * @param enmEvent The event.
+ * @param idCpu The cpu it applies to.
+ * @param pvUser The timer.
+ */
+static DECLCALLBACK(void) rtTimerLinuxMpEvent(RTMPEVENT enmEvent, RTCPUID idCpu, void *pvUser)
+{
+ PRTTIMER pTimer = (PRTTIMER)pvUser;
+ PRTTIMERLNXSUBTIMER pSubTimer = &pTimer->aSubTimers[idCpu];
+ RTSPINLOCK hSpinlock;
+
+ Assert(idCpu < pTimer->cCpus);
+
+ /*
+ * Some initial paranoia.
+ */
+ if (pTimer->u32Magic != RTTIMER_MAGIC)
+ return;
+ hSpinlock = pTimer->hSpinlock;
+ if (hSpinlock == NIL_RTSPINLOCK)
+ return;
+
+ RTSpinlockAcquire(hSpinlock);
+
+ /* Is it active? */
+ if ( !ASMAtomicUoReadBool(&pTimer->fSuspended)
+ && pTimer->u32Magic == RTTIMER_MAGIC)
+ {
+ switch (enmEvent)
+ {
+ /*
+ * Try do it without leaving the spin lock, but if we have to, retake it
+ * when we're on the right cpu.
+ */
+ case RTMPEVENT_ONLINE:
+ if (rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_MP_STARTING, RTTIMERLNXSTATE_STOPPED))
+ {
+ RTTIMERLINUXSTARTONCPUARGS Args;
+ Args.u64Now = RTTimeSystemNanoTS();
+ Args.u64First = 0;
+
+ if (RTMpCpuId() == idCpu)
+ rtTimerLnxStartSubTimer(pSubTimer, Args.u64Now, Args.u64First, true /*fPinned*/, pTimer->fHighRes);
+ else
+ {
+ rtTimerLnxSetState(&pSubTimer->enmState, RTTIMERLNXSTATE_STOPPED); /* we'll recheck it. */
+ RTSpinlockRelease(hSpinlock);
+
+ RTMpOnSpecific(idCpu, rtTimerLinuxMpStartOnCpu, pTimer, &Args);
+ return; /* we've left the spinlock */
+ }
+ }
+ break;
+
+ /*
+ * The CPU is (going) offline, make sure the sub-timer is stopped.
+ *
+ * Linux will migrate it to a different CPU, but we don't want this. The
+ * timer function is checking for this.
+ */
+ case RTMPEVENT_OFFLINE:
+ {
+ RTTIMERLNXSTATE enmState;
+ while ( (enmState = rtTimerLnxGetState(&pSubTimer->enmState)) == RTTIMERLNXSTATE_ACTIVE
+ || enmState == RTTIMERLNXSTATE_CALLBACK
+ || enmState == RTTIMERLNXSTATE_CB_RESTARTING)
+ {
+ if (enmState == RTTIMERLNXSTATE_ACTIVE)
+ {
+ if (rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_MP_STOPPING, RTTIMERLNXSTATE_ACTIVE))
+ {
+ RTSpinlockRelease(hSpinlock);
+
+ rtTimerLnxStopSubTimer(pSubTimer, pTimer->fHighRes);
+ return; /* we've left the spinlock */
+ }
+ }
+ else if (rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_CB_STOPPING, enmState))
+ break;
+
+ /* State not stable, try again. */
+ ASMNopPause();
+ }
+ break;
+ }
+ }
+ }
+
+ RTSpinlockRelease(hSpinlock);
+}
+
+#endif /* CONFIG_SMP */
+
+
+/**
+ * Callback function use by RTTimerStart via RTMpOnSpecific to start a timer
+ * running on a specific CPU.
+ *
+ * @param idCpu The current CPU.
+ * @param pvUser1 Pointer to the timer.
+ * @param pvUser2 Pointer to the argument structure.
+ */
+static DECLCALLBACK(void) rtTimerLnxStartOnSpecificCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
+{
+ PRTTIMERLINUXSTARTONCPUARGS pArgs = (PRTTIMERLINUXSTARTONCPUARGS)pvUser2;
+ PRTTIMER pTimer = (PRTTIMER)pvUser1;
+ RT_NOREF_PV(idCpu);
+ rtTimerLnxStartSubTimer(&pTimer->aSubTimers[0], pArgs->u64Now, pArgs->u64First, true /*fPinned*/, pTimer->fHighRes);
+}
+
+
+RTDECL(int) RTTimerStart(PRTTIMER pTimer, uint64_t u64First)
+{
+ RTTIMERLINUXSTARTONCPUARGS Args;
+ int rc2;
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ /*
+ * Validate.
+ */
+ AssertPtrReturn(pTimer, VERR_INVALID_HANDLE);
+ AssertReturn(pTimer->u32Magic == RTTIMER_MAGIC, VERR_INVALID_HANDLE);
+
+ if (!ASMAtomicUoReadBool(&pTimer->fSuspended))
+ return VERR_TIMER_ACTIVE;
+ RTTIMERLNX_LOG(("start %p cCpus=%d\n", pTimer, pTimer->cCpus));
+
+ Args.u64First = u64First;
+#ifdef CONFIG_SMP
+ /*
+ * Omni timer?
+ */
+ if (pTimer->fAllCpus)
+ {
+ rc2 = rtTimerLnxOmniStart(pTimer, &Args);
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc2;
+ }
+#endif
+
+ /*
+ * Simple timer - Pretty straight forward if it wasn't for restarting.
+ */
+ Args.u64Now = RTTimeSystemNanoTS();
+ ASMAtomicWriteU64(&pTimer->aSubTimers[0].uNsRestartAt, Args.u64Now + u64First);
+ for (;;)
+ {
+ RTTIMERLNXSTATE enmState = rtTimerLnxGetState(&pTimer->aSubTimers[0].enmState);
+ switch (enmState)
+ {
+ case RTTIMERLNXSTATE_STOPPED:
+ if (rtTimerLnxCmpXchgState(&pTimer->aSubTimers[0].enmState, RTTIMERLNXSTATE_STARTING, RTTIMERLNXSTATE_STOPPED))
+ {
+ ASMAtomicWriteBool(&pTimer->fSuspended, false);
+ if (!pTimer->fSpecificCpu)
+ rtTimerLnxStartSubTimer(&pTimer->aSubTimers[0], Args.u64Now, Args.u64First,
+ false /*fPinned*/, pTimer->fHighRes);
+ else
+ {
+ rc2 = RTMpOnSpecific(pTimer->idCpu, rtTimerLnxStartOnSpecificCpu, pTimer, &Args);
+ if (RT_FAILURE(rc2))
+ {
+ /* Suspend it, the cpu id is probably invalid or offline. */
+ ASMAtomicWriteBool(&pTimer->fSuspended, true);
+ rtTimerLnxSetState(&pTimer->aSubTimers[0].enmState, RTTIMERLNXSTATE_STOPPED);
+ return rc2;
+ }
+ }
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+ }
+ break;
+
+ case RTTIMERLNXSTATE_CALLBACK:
+ case RTTIMERLNXSTATE_CB_STOPPING:
+ if (rtTimerLnxCmpXchgState(&pTimer->aSubTimers[0].enmState, RTTIMERLNXSTATE_CB_RESTARTING, enmState))
+ {
+ ASMAtomicWriteBool(&pTimer->fSuspended, false);
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+ }
+ break;
+
+ default:
+ AssertMsgFailed(("%d\n", enmState));
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VERR_INTERNAL_ERROR_4;
+ }
+ ASMNopPause();
+ }
+}
+RT_EXPORT_SYMBOL(RTTimerStart);
+
+
+/**
+ * Common worker for RTTimerStop and RTTimerDestroy.
+ *
+ * @returns true if there was any active callbacks, false if not.
+ * @param pTimer The timer to stop.
+ * @param fForDestroy Whether it's RTTimerDestroy calling or not.
+ */
+static bool rtTimerLnxStop(PRTTIMER pTimer, bool fForDestroy)
+{
+ RTTIMERLNX_LOG(("lnxstop %p %d\n", pTimer, fForDestroy));
+#ifdef CONFIG_SMP
+ /*
+ * Omni timer?
+ */
+ if (pTimer->fAllCpus)
+ return rtTimerLnxOmniStop(pTimer, fForDestroy);
+#endif
+
+ /*
+ * Simple timer.
+ */
+ ASMAtomicWriteBool(&pTimer->fSuspended, true);
+ for (;;)
+ {
+ RTTIMERLNXSTATE enmState = rtTimerLnxGetState(&pTimer->aSubTimers[0].enmState);
+ switch (enmState)
+ {
+ case RTTIMERLNXSTATE_ACTIVE:
+ if (rtTimerLnxCmpXchgState(&pTimer->aSubTimers[0].enmState, RTTIMERLNXSTATE_STOPPING, RTTIMERLNXSTATE_ACTIVE))
+ {
+ rtTimerLnxStopSubTimer(&pTimer->aSubTimers[0], pTimer->fHighRes);
+ return false;
+ }
+ break;
+
+ case RTTIMERLNXSTATE_CALLBACK:
+ case RTTIMERLNXSTATE_CB_RESTARTING:
+ case RTTIMERLNXSTATE_CB_STOPPING:
+ Assert(enmState != RTTIMERLNXSTATE_CB_STOPPING || fForDestroy);
+ if (rtTimerLnxCmpXchgState(&pTimer->aSubTimers[0].enmState,
+ !fForDestroy ? RTTIMERLNXSTATE_CB_STOPPING : RTTIMERLNXSTATE_CB_DESTROYING,
+ enmState))
+ return true;
+ break;
+
+ case RTTIMERLNXSTATE_STOPPED:
+ return VINF_SUCCESS;
+
+ case RTTIMERLNXSTATE_CB_DESTROYING:
+ AssertMsgFailed(("enmState=%d pTimer=%p\n", enmState, pTimer));
+ return true;
+
+ default:
+ case RTTIMERLNXSTATE_STARTING:
+ case RTTIMERLNXSTATE_MP_STARTING:
+ case RTTIMERLNXSTATE_STOPPING:
+ case RTTIMERLNXSTATE_MP_STOPPING:
+ AssertMsgFailed(("enmState=%d pTimer=%p\n", enmState, pTimer));
+ return false;
+ }
+
+ /* State not stable, try again. */
+ ASMNopPause();
+ }
+}
+
+
+RTDECL(int) RTTimerStop(PRTTIMER pTimer)
+{
+ /*
+ * Validate.
+ */
+ IPRT_LINUX_SAVE_EFL_AC();
+ AssertPtrReturn(pTimer, VERR_INVALID_HANDLE);
+ AssertReturn(pTimer->u32Magic == RTTIMER_MAGIC, VERR_INVALID_HANDLE);
+ RTTIMERLNX_LOG(("stop %p\n", pTimer));
+
+ if (ASMAtomicUoReadBool(&pTimer->fSuspended))
+ return VERR_TIMER_SUSPENDED;
+
+ rtTimerLnxStop(pTimer, false /*fForDestroy*/);
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTTimerStop);
+
+
+RTDECL(int) RTTimerChangeInterval(PRTTIMER pTimer, uint64_t u64NanoInterval)
+{
+ unsigned long cJiffies;
+ unsigned long flFlags;
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ /*
+ * Validate.
+ */
+ AssertPtrReturn(pTimer, VERR_INVALID_HANDLE);
+ AssertReturn(pTimer->u32Magic == RTTIMER_MAGIC, VERR_INVALID_HANDLE);
+ AssertReturn(u64NanoInterval, VERR_INVALID_PARAMETER);
+ AssertReturn(u64NanoInterval < UINT64_MAX / 8, VERR_INVALID_PARAMETER);
+ AssertReturn(pTimer->u64NanoInterval, VERR_INVALID_STATE);
+ RTTIMERLNX_LOG(("change %p %llu\n", pTimer, u64NanoInterval));
+
+#ifdef RTTIMER_LINUX_WITH_HRTIMER
+ /*
+ * For the high resolution timers it is easy since we don't care so much
+ * about when it is applied to the sub-timers.
+ */
+ if (pTimer->fHighRes)
+ {
+ ASMAtomicWriteU64(&pTimer->u64NanoInterval, u64NanoInterval);
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+ }
+#endif
+
+ /*
+ * Standard timers have a bit more complicated way of calculating
+ * their interval and such. So, forget omni timers for now.
+ */
+ if (pTimer->cCpus > 1)
+ return VERR_NOT_SUPPORTED;
+
+ cJiffies = u64NanoInterval / RTTimerGetSystemGranularity();
+ if (cJiffies * RTTimerGetSystemGranularity() != u64NanoInterval)
+ cJiffies = 0;
+
+ spin_lock_irqsave(&pTimer->ChgIntLock, flFlags);
+ pTimer->aSubTimers[0].u.Std.fFirstAfterChg = true;
+ pTimer->cJiffies = cJiffies;
+ ASMAtomicWriteU64(&pTimer->u64NanoInterval, u64NanoInterval);
+ spin_unlock_irqrestore(&pTimer->ChgIntLock, flFlags);
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTTimerChangeInterval);
+
+
+RTDECL(int) RTTimerDestroy(PRTTIMER pTimer)
+{
+ bool fCanDestroy;
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ /*
+ * Validate. It's ok to pass NULL pointer.
+ */
+ if (pTimer == /*NIL_RTTIMER*/ NULL)
+ return VINF_SUCCESS;
+ AssertPtrReturn(pTimer, VERR_INVALID_HANDLE);
+ AssertReturn(pTimer->u32Magic == RTTIMER_MAGIC, VERR_INVALID_HANDLE);
+ RTTIMERLNX_LOG(("destroy %p\n", pTimer));
+/** @todo We should invalidate the magic here! */
+
+ /*
+ * Stop the timer if it's still active, then destroy it if we can.
+ */
+ if (!ASMAtomicUoReadBool(&pTimer->fSuspended))
+ fCanDestroy = rtTimerLnxStop(pTimer, true /*fForDestroy*/);
+ else
+ {
+ uint32_t iCpu = pTimer->cCpus;
+ if (pTimer->cCpus > 1)
+ RTSpinlockAcquire(pTimer->hSpinlock);
+
+ fCanDestroy = true;
+ while (iCpu-- > 0)
+ {
+ for (;;)
+ {
+ RTTIMERLNXSTATE enmState = rtTimerLnxGetState(&pTimer->aSubTimers[iCpu].enmState);
+ switch (enmState)
+ {
+ case RTTIMERLNXSTATE_CALLBACK:
+ case RTTIMERLNXSTATE_CB_RESTARTING:
+ case RTTIMERLNXSTATE_CB_STOPPING:
+ if (!rtTimerLnxCmpXchgState(&pTimer->aSubTimers[iCpu].enmState, RTTIMERLNXSTATE_CB_DESTROYING, enmState))
+ continue;
+ fCanDestroy = false;
+ break;
+
+ case RTTIMERLNXSTATE_CB_DESTROYING:
+ AssertMsgFailed(("%d\n", enmState));
+ fCanDestroy = false;
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ }
+
+ if (pTimer->cCpus > 1)
+ RTSpinlockRelease(pTimer->hSpinlock);
+ }
+
+ if (fCanDestroy)
+ {
+ /* For paranoid reasons, defer actually destroying the semaphore when
+ in atomic or interrupt context. */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 32)
+ if (in_atomic() || in_interrupt())
+#else
+ if (in_interrupt())
+#endif
+ rtR0LnxWorkqueuePush(&pTimer->DtorWorkqueueItem, rtTimerLnxDestroyDeferred);
+ else
+ rtTimerLnxDestroyIt(pTimer);
+ }
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTTimerDestroy);
+
+
+RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, uint32_t fFlags, PFNRTTIMER pfnTimer, void *pvUser)
+{
+ PRTTIMER pTimer;
+ RTCPUID iCpu;
+ unsigned cCpus;
+ int rc;
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ rtR0LnxWorkqueueFlush(); /* for 2.4 */
+ *ppTimer = NULL;
+
+ /*
+ * Validate flags.
+ */
+ if (!RTTIMER_FLAGS_ARE_VALID(fFlags))
+ {
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VERR_INVALID_PARAMETER;
+ }
+ if ( (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC)
+ && (fFlags & RTTIMER_FLAGS_CPU_ALL) != RTTIMER_FLAGS_CPU_ALL
+ && !RTMpIsCpuPossible(RTMpCpuIdFromSetIndex(fFlags & RTTIMER_FLAGS_CPU_MASK)))
+ {
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VERR_CPU_NOT_FOUND;
+ }
+
+ /*
+ * Allocate the timer handler.
+ */
+ cCpus = 1;
+#ifdef CONFIG_SMP
+ if ((fFlags & RTTIMER_FLAGS_CPU_ALL) == RTTIMER_FLAGS_CPU_ALL)
+ {
+ cCpus = RTMpGetMaxCpuId() + 1;
+ Assert(cCpus <= RTCPUSET_MAX_CPUS); /* On linux we have a 1:1 relationship between cpuid and set index. */
+ AssertReturnStmt(u64NanoInterval, IPRT_LINUX_RESTORE_EFL_AC(), VERR_NOT_IMPLEMENTED); /* We don't implement single shot on all cpus, sorry. */
+ }
+#endif
+
+ rc = RTMemAllocEx(RT_OFFSETOF(RTTIMER, aSubTimers[cCpus]), 0,
+ RTMEMALLOCEX_FLAGS_ZEROED | RTMEMALLOCEX_FLAGS_ANY_CTX_FREE, (void **)&pTimer);
+ if (RT_FAILURE(rc))
+ {
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc;
+ }
+
+ /*
+ * Initialize it.
+ */
+ pTimer->u32Magic = RTTIMER_MAGIC;
+ pTimer->hSpinlock = NIL_RTSPINLOCK;
+ pTimer->fSuspended = true;
+ pTimer->fHighRes = !!(fFlags & RTTIMER_FLAGS_HIGH_RES);
+#ifdef CONFIG_SMP
+ pTimer->fSpecificCpu = (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC) && (fFlags & RTTIMER_FLAGS_CPU_ALL) != RTTIMER_FLAGS_CPU_ALL;
+ pTimer->fAllCpus = (fFlags & RTTIMER_FLAGS_CPU_ALL) == RTTIMER_FLAGS_CPU_ALL;
+ pTimer->idCpu = pTimer->fSpecificCpu
+ ? RTMpCpuIdFromSetIndex(fFlags & RTTIMER_FLAGS_CPU_MASK)
+ : NIL_RTCPUID;
+#else
+ pTimer->fSpecificCpu = !!(fFlags & RTTIMER_FLAGS_CPU_SPECIFIC);
+ pTimer->idCpu = RTMpCpuId();
+#endif
+ pTimer->cCpus = cCpus;
+ pTimer->pfnTimer = pfnTimer;
+ pTimer->pvUser = pvUser;
+ pTimer->u64NanoInterval = u64NanoInterval;
+ pTimer->cJiffies = u64NanoInterval / RTTimerGetSystemGranularity();
+ if (pTimer->cJiffies * RTTimerGetSystemGranularity() != u64NanoInterval)
+ pTimer->cJiffies = 0;
+ spin_lock_init(&pTimer->ChgIntLock);
+
+ for (iCpu = 0; iCpu < cCpus; iCpu++)
+ {
+#ifdef RTTIMER_LINUX_WITH_HRTIMER
+ if (pTimer->fHighRes)
+ {
+ hrtimer_init(&pTimer->aSubTimers[iCpu].u.Hr.LnxTimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+ pTimer->aSubTimers[iCpu].u.Hr.LnxTimer.function = rtTimerLinuxHrCallback;
+ }
+ else
+#endif
+ {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)
+ init_timer_pinned(&pTimer->aSubTimers[iCpu].u.Std.LnxTimer);
+#else
+ init_timer(&pTimer->aSubTimers[iCpu].u.Std.LnxTimer);
+#endif
+ pTimer->aSubTimers[iCpu].u.Std.LnxTimer.data = (unsigned long)&pTimer->aSubTimers[iCpu];
+ pTimer->aSubTimers[iCpu].u.Std.LnxTimer.function = rtTimerLinuxStdCallback;
+ pTimer->aSubTimers[iCpu].u.Std.LnxTimer.expires = jiffies;
+ pTimer->aSubTimers[iCpu].u.Std.u64NextTS = 0;
+ }
+ pTimer->aSubTimers[iCpu].iTick = 0;
+ pTimer->aSubTimers[iCpu].pParent = pTimer;
+ pTimer->aSubTimers[iCpu].enmState = RTTIMERLNXSTATE_STOPPED;
+ }
+
+#ifdef CONFIG_SMP
+ /*
+ * If this is running on ALL cpus, we'll have to register a callback
+ * for MP events (so timers can be started/stopped on cpus going
+ * online/offline). We also create the spinlock for synchronizing
+ * stop/start/mp-event.
+ */
+ if (cCpus > 1)
+ {
+ int rc = RTSpinlockCreate(&pTimer->hSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "RTTimerLnx");
+ if (RT_SUCCESS(rc))
+ rc = RTMpNotificationRegister(rtTimerLinuxMpEvent, pTimer);
+ else
+ pTimer->hSpinlock = NIL_RTSPINLOCK;
+ if (RT_FAILURE(rc))
+ {
+ RTTimerDestroy(pTimer);
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc;
+ }
+ }
+#endif /* CONFIG_SMP */
+
+ RTTIMERLNX_LOG(("create %p hires=%d fFlags=%#x cCpus=%u\n", pTimer, pTimer->fHighRes, fFlags, cCpus));
+ *ppTimer = pTimer;
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTTimerCreateEx);
+
+
+RTDECL(uint32_t) RTTimerGetSystemGranularity(void)
+{
+#if 0 /** @todo Not sure if this is what we want or not... Add new API for
+ * querying the resolution of the high res timers? */
+ struct timespec Ts;
+ int rc;
+ IPRT_LINUX_SAVE_EFL_AC();
+ rc = hrtimer_get_res(CLOCK_MONOTONIC, &Ts);
+ IPRT_LINUX_RESTORE_EFL_AC();
+ if (!rc)
+ {
+ Assert(!Ts.tv_sec);
+ return Ts.tv_nsec;
+ }
+#endif
+ return RT_NS_1SEC / HZ; /* ns */
+}
+RT_EXPORT_SYMBOL(RTTimerGetSystemGranularity);
+
+
+RTDECL(int) RTTimerRequestSystemGranularity(uint32_t u32Request, uint32_t *pu32Granted)
+{
+ RT_NOREF_PV(u32Request); RT_NOREF_PV(*pu32Granted);
+ return VERR_NOT_SUPPORTED;
+}
+RT_EXPORT_SYMBOL(RTTimerRequestSystemGranularity);
+
+
+RTDECL(int) RTTimerReleaseSystemGranularity(uint32_t u32Granted)
+{
+ RT_NOREF_PV(u32Granted);
+ return VERR_NOT_SUPPORTED;
+}
+RT_EXPORT_SYMBOL(RTTimerReleaseSystemGranularity);
+
+
+RTDECL(bool) RTTimerCanDoHighResolution(void)
+{
+#ifdef RTTIMER_LINUX_WITH_HRTIMER
+ return true;
+#else
+ return false;
+#endif
+}
+RT_EXPORT_SYMBOL(RTTimerCanDoHighResolution);
+
--- /dev/null
+/* $Id: waitqueue-r0drv-linux.h $ */
+/** @file
+ * IPRT - Linux Ring-0 Driver Helpers for Abstracting Wait Queues,
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+#ifndef ___r0drv_linux_waitqueue_r0drv_linux_h
+#define ___r0drv_linux_waitqueue_r0drv_linux_h
+
+#include "the-linux-kernel.h"
+
+#include <iprt/asm-math.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
+#include <iprt/time.h>
+
+/** The resolution (nanoseconds) specified when using
+ * schedule_hrtimeout_range. */
+#define RTR0SEMLNXWAIT_RESOLUTION 50000
+
+
+/**
+ * Kernel mode Linux wait state structure.
+ */
+typedef struct RTR0SEMLNXWAIT
+{
+ /** The wait queue entry. */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
+ wait_queue_entry_t WaitQE;
+#else
+ wait_queue_t WaitQE;
+#endif
+ /** The absolute timeout given as nano seconds since the start of the
+ * monotonic clock. */
+ uint64_t uNsAbsTimeout;
+ /** The timeout in nano seconds relative to the start of the wait. */
+ uint64_t cNsRelTimeout;
+ /** The native timeout value. */
+ union
+ {
+#ifdef IPRT_LINUX_HAS_HRTIMER
+ /** The timeout when fHighRes is true. Absolute, so no updating. */
+ ktime_t KtTimeout;
+#endif
+ /** The timeout when fHighRes is false. Updated after waiting. */
+ long lTimeout;
+ } u;
+ /** Set if we use high resolution timeouts. */
+ bool fHighRes;
+ /** Set if it's an indefinite wait. */
+ bool fIndefinite;
+ /** Set if we've already timed out.
+ * Set by rtR0SemLnxWaitDoIt and read by rtR0SemLnxWaitHasTimedOut. */
+ bool fTimedOut;
+ /** TASK_INTERRUPTIBLE or TASK_UNINTERRUPTIBLE. */
+ int iWaitState;
+ /** The wait queue. */
+ wait_queue_head_t *pWaitQueue;
+} RTR0SEMLNXWAIT;
+/** Pointer to a linux wait state. */
+typedef RTR0SEMLNXWAIT *PRTR0SEMLNXWAIT;
+
+
+/**
+ * Initializes a wait.
+ *
+ * The caller MUST check the wait condition BEFORE calling this function or the
+ * timeout logic will be flawed.
+ *
+ * @returns VINF_SUCCESS or VERR_TIMEOUT.
+ * @param pWait The wait structure.
+ * @param fFlags The wait flags.
+ * @param uTimeout The timeout.
+ * @param pWaitQueue The wait queue head.
+ */
+DECLINLINE(int) rtR0SemLnxWaitInit(PRTR0SEMLNXWAIT pWait, uint32_t fFlags, uint64_t uTimeout,
+ wait_queue_head_t *pWaitQueue)
+{
+ /*
+ * Process the flags and timeout.
+ */
+ if (!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE))
+ {
+/** @todo optimize: millisecs -> nanosecs -> millisec -> jiffies */
+ if (fFlags & RTSEMWAIT_FLAGS_MILLISECS)
+ uTimeout = uTimeout < UINT64_MAX / RT_US_1SEC * RT_US_1SEC
+ ? uTimeout * RT_US_1SEC
+ : UINT64_MAX;
+ if (uTimeout == UINT64_MAX)
+ fFlags |= RTSEMWAIT_FLAGS_INDEFINITE;
+ else
+ {
+ uint64_t u64Now;
+ if (fFlags & RTSEMWAIT_FLAGS_RELATIVE)
+ {
+ if (uTimeout == 0)
+ return VERR_TIMEOUT;
+
+ u64Now = RTTimeSystemNanoTS();
+ pWait->cNsRelTimeout = uTimeout;
+ pWait->uNsAbsTimeout = u64Now + uTimeout;
+ if (pWait->uNsAbsTimeout < u64Now) /* overflow */
+ fFlags |= RTSEMWAIT_FLAGS_INDEFINITE;
+ }
+ else
+ {
+ u64Now = RTTimeSystemNanoTS();
+ if (u64Now >= uTimeout)
+ return VERR_TIMEOUT;
+
+ pWait->cNsRelTimeout = uTimeout - u64Now;
+ pWait->uNsAbsTimeout = uTimeout;
+ }
+ }
+ }
+
+ if (!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE))
+ {
+ pWait->fIndefinite = false;
+#ifdef IPRT_LINUX_HAS_HRTIMER
+ if ( (fFlags & (RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE))
+ || pWait->cNsRelTimeout < RT_NS_1SEC / HZ * 4)
+ {
+ pWait->fHighRes = true;
+# if BITS_PER_LONG < 64
+ if ( KTIME_SEC_MAX <= LONG_MAX
+ && pWait->uNsAbsTimeout >= KTIME_SEC_MAX * RT_NS_1SEC_64 + (RT_NS_1SEC - 1))
+ fFlags |= RTSEMWAIT_FLAGS_INDEFINITE;
+ else
+# endif
+ pWait->u.KtTimeout = ns_to_ktime(pWait->uNsAbsTimeout);
+ }
+ else
+#endif
+ {
+ uint64_t cJiffies = ASMMultU64ByU32DivByU32(pWait->cNsRelTimeout, HZ, RT_NS_1SEC);
+ if (cJiffies >= MAX_JIFFY_OFFSET)
+ fFlags |= RTSEMWAIT_FLAGS_INDEFINITE;
+ else
+ {
+ pWait->u.lTimeout = (long)cJiffies;
+ pWait->fHighRes = false;
+ }
+ }
+ }
+
+ if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE)
+ {
+ pWait->fIndefinite = true;
+ pWait->fHighRes = false;
+ pWait->uNsAbsTimeout = UINT64_MAX;
+ pWait->cNsRelTimeout = UINT64_MAX;
+ pWait->u.lTimeout = LONG_MAX;
+ }
+
+ pWait->fTimedOut = false;
+
+ /*
+ * Initialize the wait queue related bits.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 39)
+ init_wait((&pWait->WaitQE));
+#else
+ RT_ZERO(pWait->WaitQE);
+ init_waitqueue_entry((&pWait->WaitQE), current);
+#endif
+ pWait->pWaitQueue = pWaitQueue;
+ pWait->iWaitState = fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE
+ ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE;
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Prepares the next wait.
+ *
+ * This must be called before rtR0SemLnxWaitDoIt, and the caller should check
+ * the exit conditions in-between the two calls.
+ *
+ * @param pWait The wait structure.
+ */
+DECLINLINE(void) rtR0SemLnxWaitPrepare(PRTR0SEMLNXWAIT pWait)
+{
+ /* Make everything thru schedule*() atomic scheduling wise. (Is this correct?) */
+ prepare_to_wait(pWait->pWaitQueue, &pWait->WaitQE, pWait->iWaitState);
+}
+
+
+/**
+ * Do the actual wait.
+ *
+ * @param pWait The wait structure.
+ */
+DECLINLINE(void) rtR0SemLnxWaitDoIt(PRTR0SEMLNXWAIT pWait)
+{
+ if (pWait->fIndefinite)
+ schedule();
+#ifdef IPRT_LINUX_HAS_HRTIMER
+ else if (pWait->fHighRes)
+ {
+ int rc = schedule_hrtimeout_range(&pWait->u.KtTimeout, HRTIMER_MODE_ABS, RTR0SEMLNXWAIT_RESOLUTION);
+ if (!rc)
+ pWait->fTimedOut = true;
+ }
+#endif
+ else
+ {
+ pWait->u.lTimeout = schedule_timeout(pWait->u.lTimeout);
+ if (pWait->u.lTimeout <= 0)
+ pWait->fTimedOut = true;
+ }
+ after_wait((&pWait->WaitQE));
+}
+
+
+/**
+ * Checks if a linux wait was interrupted.
+ *
+ * @returns true / false
+ * @param pWait The wait structure.
+ * @remarks This shall be called before the first rtR0SemLnxWaitDoIt().
+ */
+DECLINLINE(bool) rtR0SemLnxWaitWasInterrupted(PRTR0SEMLNXWAIT pWait)
+{
+ return pWait->iWaitState == TASK_INTERRUPTIBLE
+ && signal_pending(current);
+}
+
+
+/**
+ * Checks if a linux wait has timed out.
+ *
+ * @returns true / false
+ * @param pWait The wait structure.
+ */
+DECLINLINE(bool) rtR0SemLnxWaitHasTimedOut(PRTR0SEMLNXWAIT pWait)
+{
+ return pWait->fTimedOut;
+}
+
+
+/**
+ * Deletes a linux wait.
+ *
+ * @param pWait The wait structure.
+ */
+DECLINLINE(void) rtR0SemLnxWaitDelete(PRTR0SEMLNXWAIT pWait)
+{
+ finish_wait(pWait->pWaitQueue, &pWait->WaitQE);
+}
+
+
+/**
+ * Gets the max resolution of the timeout machinery.
+ *
+ * @returns Resolution specified in nanoseconds.
+ */
+DECLINLINE(uint32_t) rtR0SemLnxWaitGetResolution(void)
+{
+#ifdef IPRT_LINUX_HAS_HRTIMER
+ return RTR0SEMLNXWAIT_RESOLUTION;
+#else
+ return RT_NS_1SEC / HZ; /* ns */
+#endif
+}
+
+#endif
+
--- /dev/null
+/* $Id: memobj-r0drv.cpp $ */
+/** @file
+ * IPRT - Ring-0 Memory Objects, Common Code.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP RTLOGGROUP_DEFAULT /// @todo RTLOGGROUP_MEM
+#define RTMEM_NO_WRAP_TO_EF_APIS /* circular dependency otherwise. */
+#include <iprt/memobj.h>
+#include "internal/iprt.h"
+
+#include <iprt/alloc.h>
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/log.h>
+#include <iprt/mp.h>
+#include <iprt/param.h>
+#include <iprt/process.h>
+#include <iprt/thread.h>
+
+#include "internal/memobj.h"
+
+
+/**
+ * Internal function for allocating a new memory object.
+ *
+ * @returns The allocated and initialized handle.
+ * @param cbSelf The size of the memory object handle. 0 mean default size.
+ * @param enmType The memory object type.
+ * @param pv The memory object mapping.
+ * @param cb The size of the memory object.
+ */
+DECLHIDDEN(PRTR0MEMOBJINTERNAL) rtR0MemObjNew(size_t cbSelf, RTR0MEMOBJTYPE enmType, void *pv, size_t cb)
+{
+ PRTR0MEMOBJINTERNAL pNew;
+
+ /* validate the size */
+ if (!cbSelf)
+ cbSelf = sizeof(*pNew);
+ Assert(cbSelf >= sizeof(*pNew));
+ Assert(cbSelf == (uint32_t)cbSelf);
+ AssertMsg(RT_ALIGN_Z(cb, PAGE_SIZE) == cb, ("%#zx\n", cb));
+
+ /*
+ * Allocate and initialize the object.
+ */
+ pNew = (PRTR0MEMOBJINTERNAL)RTMemAllocZ(cbSelf);
+ if (pNew)
+ {
+ pNew->u32Magic = RTR0MEMOBJ_MAGIC;
+ pNew->cbSelf = (uint32_t)cbSelf;
+ pNew->enmType = enmType;
+ pNew->fFlags = 0;
+ pNew->cb = cb;
+ pNew->pv = pv;
+ }
+ return pNew;
+}
+
+
+/**
+ * Deletes an incomplete memory object.
+ *
+ * This is for cleaning up after failures during object creation.
+ *
+ * @param pMem The incomplete memory object to delete.
+ */
+DECLHIDDEN(void) rtR0MemObjDelete(PRTR0MEMOBJINTERNAL pMem)
+{
+ if (pMem)
+ {
+ ASMAtomicUoWriteU32(&pMem->u32Magic, ~RTR0MEMOBJ_MAGIC);
+ pMem->enmType = RTR0MEMOBJTYPE_END;
+ RTMemFree(pMem);
+ }
+}
+
+
+/**
+ * Links a mapping object to a primary object.
+ *
+ * @returns IPRT status code.
+ * @retval VINF_SUCCESS on success.
+ * @retval VINF_NO_MEMORY if we couldn't expand the mapping array of the parent.
+ * @param pParent The parent (primary) memory object.
+ * @param pChild The child (mapping) memory object.
+ */
+static int rtR0MemObjLink(PRTR0MEMOBJINTERNAL pParent, PRTR0MEMOBJINTERNAL pChild)
+{
+ uint32_t i;
+
+ /* sanity */
+ Assert(rtR0MemObjIsMapping(pChild));
+ Assert(!rtR0MemObjIsMapping(pParent));
+
+ /* expand the array? */
+ i = pParent->uRel.Parent.cMappings;
+ if (i >= pParent->uRel.Parent.cMappingsAllocated)
+ {
+ void *pv = RTMemRealloc(pParent->uRel.Parent.papMappings,
+ (i + 32) * sizeof(pParent->uRel.Parent.papMappings[0]));
+ if (!pv)
+ return VERR_NO_MEMORY;
+ pParent->uRel.Parent.papMappings = (PPRTR0MEMOBJINTERNAL)pv;
+ pParent->uRel.Parent.cMappingsAllocated = i + 32;
+ Assert(i == pParent->uRel.Parent.cMappings);
+ }
+
+ /* do the linking. */
+ pParent->uRel.Parent.papMappings[i] = pChild;
+ pParent->uRel.Parent.cMappings++;
+ pChild->uRel.Child.pParent = pParent;
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * 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)
+{
+ /* Validate the object handle. */
+ PRTR0MEMOBJINTERNAL pMem;
+ AssertPtrReturn(MemObj, false);
+ pMem = (PRTR0MEMOBJINTERNAL)MemObj;
+ AssertMsgReturn(pMem->u32Magic == RTR0MEMOBJ_MAGIC, ("%p: %#x\n", pMem, pMem->u32Magic), false);
+ AssertMsgReturn(pMem->enmType > RTR0MEMOBJTYPE_INVALID && pMem->enmType < RTR0MEMOBJTYPE_END, ("%p: %d\n", pMem, pMem->enmType), false);
+
+ /* hand it on to the inlined worker. */
+ return rtR0MemObjIsMapping(pMem);
+}
+RT_EXPORT_SYMBOL(RTR0MemObjIsMapping);
+
+
+/**
+ * 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)
+{
+ /* Validate the object handle. */
+ PRTR0MEMOBJINTERNAL pMem;
+ if (RT_UNLIKELY(MemObj == NIL_RTR0MEMOBJ))
+ return NULL;
+ AssertPtrReturn(MemObj, NULL);
+ pMem = (PRTR0MEMOBJINTERNAL)MemObj;
+ AssertMsgReturn(pMem->u32Magic == RTR0MEMOBJ_MAGIC, ("%p: %#x\n", pMem, pMem->u32Magic), NULL);
+ AssertMsgReturn(pMem->enmType > RTR0MEMOBJTYPE_INVALID && pMem->enmType < RTR0MEMOBJTYPE_END, ("%p: %d\n", pMem, pMem->enmType), NULL);
+
+ /* return the mapping address. */
+ return pMem->pv;
+}
+RT_EXPORT_SYMBOL(RTR0MemObjAddress);
+
+
+/**
+ * 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)
+{
+ PRTR0MEMOBJINTERNAL pMem;
+
+ /* Validate the object handle. */
+ if (RT_UNLIKELY(MemObj == NIL_RTR0MEMOBJ))
+ return NIL_RTR3PTR;
+ AssertPtrReturn(MemObj, NIL_RTR3PTR);
+ pMem = (PRTR0MEMOBJINTERNAL)MemObj;
+ AssertMsgReturn(pMem->u32Magic == RTR0MEMOBJ_MAGIC, ("%p: %#x\n", pMem, pMem->u32Magic), NIL_RTR3PTR);
+ AssertMsgReturn(pMem->enmType > RTR0MEMOBJTYPE_INVALID && pMem->enmType < RTR0MEMOBJTYPE_END, ("%p: %d\n", pMem, pMem->enmType), NIL_RTR3PTR);
+ if (RT_UNLIKELY( ( pMem->enmType != RTR0MEMOBJTYPE_MAPPING
+ || pMem->u.Mapping.R0Process == NIL_RTR0PROCESS)
+ && ( pMem->enmType != RTR0MEMOBJTYPE_LOCK
+ || pMem->u.Lock.R0Process == NIL_RTR0PROCESS)
+ && ( pMem->enmType != RTR0MEMOBJTYPE_PHYS_NC
+ || pMem->u.Lock.R0Process == NIL_RTR0PROCESS)
+ && ( pMem->enmType != RTR0MEMOBJTYPE_RES_VIRT
+ || pMem->u.ResVirt.R0Process == NIL_RTR0PROCESS)))
+ return NIL_RTR3PTR;
+
+ /* return the mapping address. */
+ return (RTR3PTR)pMem->pv;
+}
+RT_EXPORT_SYMBOL(RTR0MemObjAddressR3);
+
+
+/**
+ * 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)
+{
+ PRTR0MEMOBJINTERNAL pMem;
+
+ /* Validate the object handle. */
+ if (RT_UNLIKELY(MemObj == NIL_RTR0MEMOBJ))
+ return 0;
+ AssertPtrReturn(MemObj, 0);
+ pMem = (PRTR0MEMOBJINTERNAL)MemObj;
+ AssertMsgReturn(pMem->u32Magic == RTR0MEMOBJ_MAGIC, ("%p: %#x\n", pMem, pMem->u32Magic), 0);
+ AssertMsgReturn(pMem->enmType > RTR0MEMOBJTYPE_INVALID && pMem->enmType < RTR0MEMOBJTYPE_END, ("%p: %d\n", pMem, pMem->enmType), 0);
+ AssertMsg(RT_ALIGN_Z(pMem->cb, PAGE_SIZE) == pMem->cb, ("%#zx\n", pMem->cb));
+
+ /* return the size. */
+ return pMem->cb;
+}
+RT_EXPORT_SYMBOL(RTR0MemObjSize);
+
+
+/**
+ * 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.
+ */
+/* Work around gcc bug 55940 */
+#if defined(__GNUC__) && defined(RT_ARCH_X86) && (__GNUC__ * 100 + __GNUC_MINOR__) == 407
+ __attribute__((__optimize__ ("no-shrink-wrap")))
+#endif
+RTR0DECL(RTHCPHYS) RTR0MemObjGetPagePhysAddr(RTR0MEMOBJ MemObj, size_t iPage)
+{
+ /* Validate the object handle. */
+ PRTR0MEMOBJINTERNAL pMem;
+ size_t cPages;
+ AssertPtrReturn(MemObj, NIL_RTHCPHYS);
+ pMem = (PRTR0MEMOBJINTERNAL)MemObj;
+ AssertReturn(pMem->u32Magic == RTR0MEMOBJ_MAGIC, NIL_RTHCPHYS);
+ AssertReturn(pMem->enmType > RTR0MEMOBJTYPE_INVALID && pMem->enmType < RTR0MEMOBJTYPE_END, NIL_RTHCPHYS);
+ AssertMsgReturn(pMem->u32Magic == RTR0MEMOBJ_MAGIC, ("%p: %#x\n", pMem, pMem->u32Magic), NIL_RTHCPHYS);
+ AssertMsgReturn(pMem->enmType > RTR0MEMOBJTYPE_INVALID && pMem->enmType < RTR0MEMOBJTYPE_END, ("%p: %d\n", pMem, pMem->enmType), NIL_RTHCPHYS);
+ cPages = (pMem->cb >> PAGE_SHIFT);
+ if (iPage >= cPages)
+ {
+ /* permit: while (RTR0MemObjGetPagePhysAddr(pMem, iPage++) != NIL_RTHCPHYS) {} */
+ if (iPage == cPages)
+ return NIL_RTHCPHYS;
+ AssertReturn(iPage < (pMem->cb >> PAGE_SHIFT), NIL_RTHCPHYS);
+ }
+
+ /*
+ * We know the address of physically contiguous allocations and mappings.
+ */
+ if (pMem->enmType == RTR0MEMOBJTYPE_CONT)
+ return pMem->u.Cont.Phys + iPage * PAGE_SIZE;
+ if (pMem->enmType == RTR0MEMOBJTYPE_PHYS)
+ return pMem->u.Phys.PhysBase + iPage * PAGE_SIZE;
+
+ /*
+ * Do the job.
+ */
+ return rtR0MemObjNativeGetPagePhysAddr(pMem, iPage);
+}
+RT_EXPORT_SYMBOL(RTR0MemObjGetPagePhysAddr);
+
+
+/**
+ * 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)
+{
+ /*
+ * Validate the object handle.
+ */
+ PRTR0MEMOBJINTERNAL pMem;
+ int rc;
+
+ if (MemObj == NIL_RTR0MEMOBJ)
+ return VINF_SUCCESS;
+ AssertPtrReturn(MemObj, VERR_INVALID_HANDLE);
+ pMem = (PRTR0MEMOBJINTERNAL)MemObj;
+ AssertReturn(pMem->u32Magic == RTR0MEMOBJ_MAGIC, VERR_INVALID_HANDLE);
+ AssertReturn(pMem->enmType > RTR0MEMOBJTYPE_INVALID && pMem->enmType < RTR0MEMOBJTYPE_END, VERR_INVALID_HANDLE);
+ RT_ASSERT_PREEMPTIBLE();
+
+ /*
+ * Deal with mappings according to fFreeMappings.
+ */
+ if ( !rtR0MemObjIsMapping(pMem)
+ && pMem->uRel.Parent.cMappings > 0)
+ {
+ /* fail if not requested to free mappings. */
+ if (!fFreeMappings)
+ return VERR_MEMORY_BUSY;
+
+ while (pMem->uRel.Parent.cMappings > 0)
+ {
+ PRTR0MEMOBJINTERNAL pChild = pMem->uRel.Parent.papMappings[--pMem->uRel.Parent.cMappings];
+ pMem->uRel.Parent.papMappings[pMem->uRel.Parent.cMappings] = NULL;
+
+ /* sanity checks. */
+ AssertPtr(pChild);
+ AssertFatal(pChild->u32Magic == RTR0MEMOBJ_MAGIC);
+ AssertFatal(pChild->enmType > RTR0MEMOBJTYPE_INVALID && pChild->enmType < RTR0MEMOBJTYPE_END);
+ AssertFatal(rtR0MemObjIsMapping(pChild));
+
+ /* free the mapping. */
+ rc = rtR0MemObjNativeFree(pChild);
+ if (RT_FAILURE(rc))
+ {
+ Log(("RTR0MemObjFree: failed to free mapping %p: %p %#zx; rc=%Rrc\n", pChild, pChild->pv, pChild->cb, rc));
+ pMem->uRel.Parent.papMappings[pMem->uRel.Parent.cMappings++] = pChild;
+ return rc;
+ }
+ }
+ }
+
+ /*
+ * Free this object.
+ */
+ rc = rtR0MemObjNativeFree(pMem);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Ok, it was freed just fine. Now, if it's a mapping we'll have to remove it from the parent.
+ */
+ if (rtR0MemObjIsMapping(pMem))
+ {
+ PRTR0MEMOBJINTERNAL pParent = pMem->uRel.Child.pParent;
+ uint32_t i;
+
+ /* sanity checks */
+ AssertPtr(pParent);
+ AssertFatal(pParent->u32Magic == RTR0MEMOBJ_MAGIC);
+ AssertFatal(pParent->enmType > RTR0MEMOBJTYPE_INVALID && pParent->enmType < RTR0MEMOBJTYPE_END);
+ AssertFatal(!rtR0MemObjIsMapping(pParent));
+ AssertFatal(pParent->uRel.Parent.cMappings > 0);
+ AssertPtr(pParent->uRel.Parent.papMappings);
+
+ /* locate and remove from the array of mappings. */
+ i = pParent->uRel.Parent.cMappings;
+ while (i-- > 0)
+ {
+ if (pParent->uRel.Parent.papMappings[i] == pMem)
+ {
+ pParent->uRel.Parent.papMappings[i] = pParent->uRel.Parent.papMappings[--pParent->uRel.Parent.cMappings];
+ break;
+ }
+ }
+ Assert(i != UINT32_MAX);
+ }
+ else
+ Assert(pMem->uRel.Parent.cMappings == 0);
+
+ /*
+ * Finally, destroy the handle.
+ */
+ pMem->u32Magic++;
+ pMem->enmType = RTR0MEMOBJTYPE_END;
+ if (!rtR0MemObjIsMapping(pMem))
+ RTMemFree(pMem->uRel.Parent.papMappings);
+ RTMemFree(pMem);
+ }
+ else
+ Log(("RTR0MemObjFree: failed to free %p: %d %p %#zx; rc=%Rrc\n",
+ pMem, pMem->enmType, pMem->pv, pMem->cb, rc));
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTR0MemObjFree);
+
+
+
+RTR0DECL(int) RTR0MemObjAllocPageTag(PRTR0MEMOBJ pMemObj, size_t cb, bool fExecutable, const char *pszTag)
+{
+ /* sanity checks. */
+ const size_t cbAligned = RT_ALIGN_Z(cb, PAGE_SIZE);
+ AssertPtrReturn(pMemObj, VERR_INVALID_POINTER);
+ *pMemObj = NIL_RTR0MEMOBJ;
+ AssertReturn(cb > 0, VERR_INVALID_PARAMETER);
+ AssertReturn(cb <= cbAligned, VERR_INVALID_PARAMETER);
+ RT_ASSERT_PREEMPTIBLE();
+
+ RT_NOREF_PV(pszTag);
+
+ /* do the allocation. */
+ return rtR0MemObjNativeAllocPage(pMemObj, cbAligned, fExecutable);
+}
+RT_EXPORT_SYMBOL(RTR0MemObjAllocPageTag);
+
+
+RTR0DECL(int) RTR0MemObjAllocLowTag(PRTR0MEMOBJ pMemObj, size_t cb, bool fExecutable, const char *pszTag)
+{
+ /* sanity checks. */
+ const size_t cbAligned = RT_ALIGN_Z(cb, PAGE_SIZE);
+ AssertPtrReturn(pMemObj, VERR_INVALID_POINTER);
+ *pMemObj = NIL_RTR0MEMOBJ;
+ AssertReturn(cb > 0, VERR_INVALID_PARAMETER);
+ AssertReturn(cb <= cbAligned, VERR_INVALID_PARAMETER);
+ RT_ASSERT_PREEMPTIBLE();
+
+ RT_NOREF_PV(pszTag);
+
+ /* do the allocation. */
+ return rtR0MemObjNativeAllocLow(pMemObj, cbAligned, fExecutable);
+}
+RT_EXPORT_SYMBOL(RTR0MemObjAllocLowTag);
+
+
+RTR0DECL(int) RTR0MemObjAllocContTag(PRTR0MEMOBJ pMemObj, size_t cb, bool fExecutable, const char *pszTag)
+{
+ /* sanity checks. */
+ const size_t cbAligned = RT_ALIGN_Z(cb, PAGE_SIZE);
+ AssertPtrReturn(pMemObj, VERR_INVALID_POINTER);
+ *pMemObj = NIL_RTR0MEMOBJ;
+ AssertReturn(cb > 0, VERR_INVALID_PARAMETER);
+ AssertReturn(cb <= cbAligned, VERR_INVALID_PARAMETER);
+ RT_ASSERT_PREEMPTIBLE();
+
+ RT_NOREF_PV(pszTag);
+
+ /* do the allocation. */
+ return rtR0MemObjNativeAllocCont(pMemObj, cbAligned, fExecutable);
+}
+RT_EXPORT_SYMBOL(RTR0MemObjAllocContTag);
+
+
+RTR0DECL(int) RTR0MemObjLockUserTag(PRTR0MEMOBJ pMemObj, RTR3PTR R3Ptr, size_t cb,
+ uint32_t fAccess, RTR0PROCESS R0Process, const char *pszTag)
+{
+ /* sanity checks. */
+ const size_t cbAligned = RT_ALIGN_Z(cb + (R3Ptr & PAGE_OFFSET_MASK), PAGE_SIZE);
+ RTR3PTR const R3PtrAligned = (R3Ptr & ~(RTR3PTR)PAGE_OFFSET_MASK);
+ AssertPtrReturn(pMemObj, VERR_INVALID_POINTER);
+ *pMemObj = NIL_RTR0MEMOBJ;
+ AssertReturn(cb > 0, VERR_INVALID_PARAMETER);
+ AssertReturn(cb <= cbAligned, VERR_INVALID_PARAMETER);
+ if (R0Process == NIL_RTR0PROCESS)
+ R0Process = RTR0ProcHandleSelf();
+ AssertReturn(!(fAccess & ~(RTMEM_PROT_READ | RTMEM_PROT_WRITE)), VERR_INVALID_PARAMETER);
+ AssertReturn(fAccess, VERR_INVALID_PARAMETER);
+ RT_ASSERT_PREEMPTIBLE();
+
+ RT_NOREF_PV(pszTag);
+
+ /* do the locking. */
+ return rtR0MemObjNativeLockUser(pMemObj, R3PtrAligned, cbAligned, fAccess, R0Process);
+}
+RT_EXPORT_SYMBOL(RTR0MemObjLockUserTag);
+
+
+RTR0DECL(int) RTR0MemObjLockKernelTag(PRTR0MEMOBJ pMemObj, void *pv, size_t cb, uint32_t fAccess, const char *pszTag)
+{
+ /* sanity checks. */
+ const size_t cbAligned = RT_ALIGN_Z(cb + ((uintptr_t)pv & PAGE_OFFSET_MASK), PAGE_SIZE);
+ void * const pvAligned = (void *)((uintptr_t)pv & ~(uintptr_t)PAGE_OFFSET_MASK);
+ AssertPtrReturn(pMemObj, VERR_INVALID_POINTER);
+ *pMemObj = NIL_RTR0MEMOBJ;
+ AssertReturn(cb > 0, VERR_INVALID_PARAMETER);
+ AssertReturn(cb <= cbAligned, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pvAligned, VERR_INVALID_POINTER);
+ AssertReturn(!(fAccess & ~(RTMEM_PROT_READ | RTMEM_PROT_WRITE)), VERR_INVALID_PARAMETER);
+ AssertReturn(fAccess, VERR_INVALID_PARAMETER);
+ RT_ASSERT_PREEMPTIBLE();
+
+ RT_NOREF_PV(pszTag);
+
+ /* do the allocation. */
+ return rtR0MemObjNativeLockKernel(pMemObj, pvAligned, cbAligned, fAccess);
+}
+RT_EXPORT_SYMBOL(RTR0MemObjLockKernelTag);
+
+
+RTR0DECL(int) RTR0MemObjAllocPhysTag(PRTR0MEMOBJ pMemObj, size_t cb, RTHCPHYS PhysHighest, const char *pszTag)
+{
+ /* sanity checks. */
+ const size_t cbAligned = RT_ALIGN_Z(cb, PAGE_SIZE);
+ AssertPtrReturn(pMemObj, VERR_INVALID_POINTER);
+ *pMemObj = NIL_RTR0MEMOBJ;
+ AssertReturn(cb > 0, VERR_INVALID_PARAMETER);
+ AssertReturn(cb <= cbAligned, VERR_INVALID_PARAMETER);
+ AssertReturn(PhysHighest >= cb, VERR_INVALID_PARAMETER);
+ RT_ASSERT_PREEMPTIBLE();
+
+ RT_NOREF_PV(pszTag);
+
+ /* do the allocation. */
+ return rtR0MemObjNativeAllocPhys(pMemObj, cbAligned, PhysHighest, PAGE_SIZE /* page aligned */);
+}
+RT_EXPORT_SYMBOL(RTR0MemObjAllocPhysTag);
+
+
+RTR0DECL(int) RTR0MemObjAllocPhysExTag(PRTR0MEMOBJ pMemObj, size_t cb, RTHCPHYS PhysHighest, size_t uAlignment, const char *pszTag)
+{
+ /* sanity checks. */
+ const size_t cbAligned = RT_ALIGN_Z(cb, PAGE_SIZE);
+ AssertPtrReturn(pMemObj, VERR_INVALID_POINTER);
+ *pMemObj = NIL_RTR0MEMOBJ;
+ AssertReturn(cb > 0, VERR_INVALID_PARAMETER);
+ AssertReturn(cb <= cbAligned, VERR_INVALID_PARAMETER);
+ AssertReturn(PhysHighest >= cb, VERR_INVALID_PARAMETER);
+ if (uAlignment == 0)
+ uAlignment = PAGE_SIZE;
+ AssertReturn( uAlignment == PAGE_SIZE
+ || uAlignment == _2M
+ || uAlignment == _4M
+ || uAlignment == _1G,
+ VERR_INVALID_PARAMETER);
+#if HC_ARCH_BITS == 32
+ /* Memory allocated in this way is typically mapped into kernel space as well; simply
+ don't allow this on 32 bits hosts as the kernel space is too crowded already. */
+ if (uAlignment != PAGE_SIZE)
+ return VERR_NOT_SUPPORTED;
+#endif
+ RT_ASSERT_PREEMPTIBLE();
+
+ RT_NOREF_PV(pszTag);
+
+ /* do the allocation. */
+ return rtR0MemObjNativeAllocPhys(pMemObj, cbAligned, PhysHighest, uAlignment);
+}
+RT_EXPORT_SYMBOL(RTR0MemObjAllocPhysExTag);
+
+
+RTR0DECL(int) RTR0MemObjAllocPhysNCTag(PRTR0MEMOBJ pMemObj, size_t cb, RTHCPHYS PhysHighest, const char *pszTag)
+{
+ /* sanity checks. */
+ const size_t cbAligned = RT_ALIGN_Z(cb, PAGE_SIZE);
+ AssertPtrReturn(pMemObj, VERR_INVALID_POINTER);
+ *pMemObj = NIL_RTR0MEMOBJ;
+ AssertReturn(cb > 0, VERR_INVALID_PARAMETER);
+ AssertReturn(cb <= cbAligned, VERR_INVALID_PARAMETER);
+ AssertReturn(PhysHighest >= cb, VERR_INVALID_PARAMETER);
+ RT_ASSERT_PREEMPTIBLE();
+
+ RT_NOREF_PV(pszTag);
+
+ /* do the allocation. */
+ return rtR0MemObjNativeAllocPhysNC(pMemObj, cbAligned, PhysHighest);
+}
+RT_EXPORT_SYMBOL(RTR0MemObjAllocPhysNCTag);
+
+
+RTR0DECL(int) RTR0MemObjEnterPhysTag(PRTR0MEMOBJ pMemObj, RTHCPHYS Phys, size_t cb, uint32_t uCachePolicy, const char *pszTag)
+{
+ /* sanity checks. */
+ const size_t cbAligned = RT_ALIGN_Z(cb + (Phys & PAGE_OFFSET_MASK), PAGE_SIZE);
+ const RTHCPHYS PhysAligned = Phys & ~(RTHCPHYS)PAGE_OFFSET_MASK;
+ AssertPtrReturn(pMemObj, VERR_INVALID_POINTER);
+ *pMemObj = NIL_RTR0MEMOBJ;
+ AssertReturn(cb > 0, VERR_INVALID_PARAMETER);
+ AssertReturn(cb <= cbAligned, VERR_INVALID_PARAMETER);
+ AssertReturn(Phys != NIL_RTHCPHYS, VERR_INVALID_PARAMETER);
+ AssertReturn( uCachePolicy == RTMEM_CACHE_POLICY_DONT_CARE
+ || uCachePolicy == RTMEM_CACHE_POLICY_MMIO,
+ VERR_INVALID_PARAMETER);
+ RT_ASSERT_PREEMPTIBLE();
+
+ RT_NOREF_PV(pszTag);
+
+ /* do the allocation. */
+ return rtR0MemObjNativeEnterPhys(pMemObj, PhysAligned, cbAligned, uCachePolicy);
+}
+RT_EXPORT_SYMBOL(RTR0MemObjEnterPhysTag);
+
+
+RTR0DECL(int) RTR0MemObjReserveKernelTag(PRTR0MEMOBJ pMemObj, void *pvFixed, size_t cb, size_t uAlignment, const char *pszTag)
+{
+ /* sanity checks. */
+ const size_t cbAligned = RT_ALIGN_Z(cb, PAGE_SIZE);
+ AssertPtrReturn(pMemObj, VERR_INVALID_POINTER);
+ *pMemObj = NIL_RTR0MEMOBJ;
+ if (uAlignment == 0)
+ uAlignment = PAGE_SIZE;
+ AssertReturn(uAlignment == PAGE_SIZE || uAlignment == _2M || uAlignment == _4M, VERR_INVALID_PARAMETER);
+ AssertReturn(cb > 0, VERR_INVALID_PARAMETER);
+ AssertReturn(cb <= cbAligned, VERR_INVALID_PARAMETER);
+ if (pvFixed != (void *)-1)
+ AssertReturn(!((uintptr_t)pvFixed & (uAlignment - 1)), VERR_INVALID_PARAMETER);
+ RT_ASSERT_PREEMPTIBLE();
+
+ RT_NOREF_PV(pszTag);
+
+ /* do the reservation. */
+ return rtR0MemObjNativeReserveKernel(pMemObj, pvFixed, cbAligned, uAlignment);
+}
+RT_EXPORT_SYMBOL(RTR0MemObjReserveKernelTag);
+
+
+RTR0DECL(int) RTR0MemObjReserveUserTag(PRTR0MEMOBJ pMemObj, RTR3PTR R3PtrFixed, size_t cb,
+ size_t uAlignment, RTR0PROCESS R0Process, const char *pszTag)
+{
+ /* sanity checks. */
+ const size_t cbAligned = RT_ALIGN_Z(cb, PAGE_SIZE);
+ AssertPtrReturn(pMemObj, VERR_INVALID_POINTER);
+ *pMemObj = NIL_RTR0MEMOBJ;
+ if (uAlignment == 0)
+ uAlignment = PAGE_SIZE;
+ AssertReturn(uAlignment == PAGE_SIZE || uAlignment == _2M || uAlignment == _4M, VERR_INVALID_PARAMETER);
+ AssertReturn(cb > 0, VERR_INVALID_PARAMETER);
+ AssertReturn(cb <= cbAligned, VERR_INVALID_PARAMETER);
+ if (R3PtrFixed != (RTR3PTR)-1)
+ AssertReturn(!(R3PtrFixed & (uAlignment - 1)), VERR_INVALID_PARAMETER);
+ if (R0Process == NIL_RTR0PROCESS)
+ R0Process = RTR0ProcHandleSelf();
+ RT_ASSERT_PREEMPTIBLE();
+
+ RT_NOREF_PV(pszTag);
+
+ /* do the reservation. */
+ return rtR0MemObjNativeReserveUser(pMemObj, R3PtrFixed, cbAligned, uAlignment, R0Process);
+}
+RT_EXPORT_SYMBOL(RTR0MemObjReserveUserTag);
+
+
+RTR0DECL(int) RTR0MemObjMapKernelTag(PRTR0MEMOBJ pMemObj, RTR0MEMOBJ MemObjToMap, void *pvFixed,
+ size_t uAlignment, unsigned fProt, const char *pszTag)
+{
+ return RTR0MemObjMapKernelExTag(pMemObj, MemObjToMap, pvFixed, uAlignment, fProt, 0, 0, pszTag);
+}
+RT_EXPORT_SYMBOL(RTR0MemObjMapKernelTag);
+
+
+RTR0DECL(int) RTR0MemObjMapKernelExTag(PRTR0MEMOBJ pMemObj, RTR0MEMOBJ MemObjToMap, void *pvFixed, size_t uAlignment,
+ unsigned fProt, size_t offSub, size_t cbSub, const char *pszTag)
+{
+ PRTR0MEMOBJINTERNAL pMemToMap;
+ PRTR0MEMOBJINTERNAL pNew;
+ int rc;
+
+ /* sanity checks. */
+ AssertPtrReturn(pMemObj, VERR_INVALID_POINTER);
+ *pMemObj = NIL_RTR0MEMOBJ;
+ AssertPtrReturn(MemObjToMap, VERR_INVALID_HANDLE);
+ pMemToMap = (PRTR0MEMOBJINTERNAL)MemObjToMap;
+ AssertReturn(pMemToMap->u32Magic == RTR0MEMOBJ_MAGIC, VERR_INVALID_HANDLE);
+ AssertReturn(pMemToMap->enmType > RTR0MEMOBJTYPE_INVALID && pMemToMap->enmType < RTR0MEMOBJTYPE_END, VERR_INVALID_HANDLE);
+ AssertReturn(!rtR0MemObjIsMapping(pMemToMap), VERR_INVALID_PARAMETER);
+ AssertReturn(pMemToMap->enmType != RTR0MEMOBJTYPE_RES_VIRT, VERR_INVALID_PARAMETER);
+ if (uAlignment == 0)
+ uAlignment = PAGE_SIZE;
+ AssertReturn(uAlignment == PAGE_SIZE || uAlignment == _2M || uAlignment == _4M, VERR_INVALID_PARAMETER);
+ if (pvFixed != (void *)-1)
+ AssertReturn(!((uintptr_t)pvFixed & (uAlignment - 1)), VERR_INVALID_PARAMETER);
+ AssertReturn(fProt != RTMEM_PROT_NONE, VERR_INVALID_PARAMETER);
+ AssertReturn(!(fProt & ~(RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC)), VERR_INVALID_PARAMETER);
+ AssertReturn(!(offSub & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
+ AssertReturn(offSub < pMemToMap->cb, VERR_INVALID_PARAMETER);
+ AssertReturn(!(cbSub & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
+ AssertReturn(cbSub <= pMemToMap->cb, VERR_INVALID_PARAMETER);
+ AssertReturn((!offSub && !cbSub) || (offSub + cbSub) <= pMemToMap->cb, VERR_INVALID_PARAMETER);
+ RT_ASSERT_PREEMPTIBLE();
+
+ RT_NOREF_PV(pszTag);
+
+ /* adjust the request to simplify the native code. */
+ if (offSub == 0 && cbSub == pMemToMap->cb)
+ cbSub = 0;
+
+ /* do the mapping. */
+ rc = rtR0MemObjNativeMapKernel(&pNew, pMemToMap, pvFixed, uAlignment, fProt, offSub, cbSub);
+ if (RT_SUCCESS(rc))
+ {
+ /* link it. */
+ rc = rtR0MemObjLink(pMemToMap, pNew);
+ if (RT_SUCCESS(rc))
+ *pMemObj = pNew;
+ else
+ {
+ /* damn, out of memory. bail out. */
+ int rc2 = rtR0MemObjNativeFree(pNew);
+ AssertRC(rc2);
+ pNew->u32Magic++;
+ pNew->enmType = RTR0MEMOBJTYPE_END;
+ RTMemFree(pNew);
+ }
+ }
+
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTR0MemObjMapKernelExTag);
+
+
+RTR0DECL(int) RTR0MemObjMapUserTag(PRTR0MEMOBJ pMemObj, RTR0MEMOBJ MemObjToMap, RTR3PTR R3PtrFixed,
+ size_t uAlignment, unsigned fProt, RTR0PROCESS R0Process, const char *pszTag)
+{
+ /* sanity checks. */
+ PRTR0MEMOBJINTERNAL pMemToMap;
+ PRTR0MEMOBJINTERNAL pNew;
+ int rc;
+ AssertPtrReturn(pMemObj, VERR_INVALID_POINTER);
+ pMemToMap = (PRTR0MEMOBJINTERNAL)MemObjToMap;
+ *pMemObj = NIL_RTR0MEMOBJ;
+ AssertPtrReturn(MemObjToMap, VERR_INVALID_HANDLE);
+ AssertReturn(pMemToMap->u32Magic == RTR0MEMOBJ_MAGIC, VERR_INVALID_HANDLE);
+ AssertReturn(pMemToMap->enmType > RTR0MEMOBJTYPE_INVALID && pMemToMap->enmType < RTR0MEMOBJTYPE_END, VERR_INVALID_HANDLE);
+ AssertReturn(!rtR0MemObjIsMapping(pMemToMap), VERR_INVALID_PARAMETER);
+ AssertReturn(pMemToMap->enmType != RTR0MEMOBJTYPE_RES_VIRT, VERR_INVALID_PARAMETER);
+ if (uAlignment == 0)
+ uAlignment = PAGE_SIZE;
+ AssertReturn(uAlignment == PAGE_SIZE || uAlignment == _2M || uAlignment == _4M, VERR_INVALID_PARAMETER);
+ if (R3PtrFixed != (RTR3PTR)-1)
+ AssertReturn(!(R3PtrFixed & (uAlignment - 1)), VERR_INVALID_PARAMETER);
+ AssertReturn(fProt != RTMEM_PROT_NONE, VERR_INVALID_PARAMETER);
+ AssertReturn(!(fProt & ~(RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC)), VERR_INVALID_PARAMETER);
+ if (R0Process == NIL_RTR0PROCESS)
+ R0Process = RTR0ProcHandleSelf();
+ RT_ASSERT_PREEMPTIBLE();
+
+ RT_NOREF_PV(pszTag);
+
+ /* do the mapping. */
+ rc = rtR0MemObjNativeMapUser(&pNew, pMemToMap, R3PtrFixed, uAlignment, fProt, R0Process);
+ if (RT_SUCCESS(rc))
+ {
+ /* link it. */
+ rc = rtR0MemObjLink(pMemToMap, pNew);
+ if (RT_SUCCESS(rc))
+ *pMemObj = pNew;
+ else
+ {
+ /* damn, out of memory. bail out. */
+ int rc2 = rtR0MemObjNativeFree(pNew);
+ AssertRC(rc2);
+ pNew->u32Magic++;
+ pNew->enmType = RTR0MEMOBJTYPE_END;
+ RTMemFree(pNew);
+ }
+ }
+
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTR0MemObjMapUserTag);
+
+
+RTR0DECL(int) RTR0MemObjProtect(RTR0MEMOBJ hMemObj, size_t offSub, size_t cbSub, uint32_t fProt)
+{
+ PRTR0MEMOBJINTERNAL pMemObj;
+ int rc;
+
+ /* sanity checks. */
+ pMemObj = (PRTR0MEMOBJINTERNAL)hMemObj;
+ AssertPtrReturn(pMemObj, VERR_INVALID_HANDLE);
+ AssertReturn(pMemObj->u32Magic == RTR0MEMOBJ_MAGIC, VERR_INVALID_HANDLE);
+ AssertReturn(pMemObj->enmType > RTR0MEMOBJTYPE_INVALID && pMemObj->enmType < RTR0MEMOBJTYPE_END, VERR_INVALID_HANDLE);
+ AssertReturn(rtR0MemObjIsProtectable(pMemObj), VERR_INVALID_PARAMETER);
+ AssertReturn(!(offSub & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
+ AssertReturn(offSub < pMemObj->cb, VERR_INVALID_PARAMETER);
+ AssertReturn(!(cbSub & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
+ AssertReturn(cbSub <= pMemObj->cb, VERR_INVALID_PARAMETER);
+ AssertReturn(offSub + cbSub <= pMemObj->cb, VERR_INVALID_PARAMETER);
+ AssertReturn(!(fProt & ~(RTMEM_PROT_NONE | RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC)), VERR_INVALID_PARAMETER);
+ RT_ASSERT_PREEMPTIBLE();
+
+ /* do the job */
+ rc = rtR0MemObjNativeProtect(pMemObj, offSub, cbSub, fProt);
+ if (RT_SUCCESS(rc))
+ pMemObj->fFlags |= RTR0MEMOBJ_FLAGS_PROT_CHANGED; /* record it */
+
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTR0MemObjProtect);
+
--- /dev/null
+/* $Id: mp-r0drv.h $ */
+/** @file
+ * IPRT - Multiprocessor, Ring-0 Driver, Internal Header.
+ */
+
+/*
+ * Copyright (C) 2008-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___r0drv_mp_r0drv_h
+#define ___r0drv_mp_r0drv_h
+
+#include <iprt/mp.h>
+
+RT_C_DECLS_BEGIN
+
+/**
+ * MP callback
+ *
+ * @param idCpu CPU id
+ * @param pvUser1 The first user argument.
+ * @param pvUser2 The second user argument.
+ */
+typedef DECLCALLBACK(void) FNMPWORKER(RTCPUID idCpu, void *pvUser1, void *pvUser2);
+/** Pointer to a FNMPWORKER(). */
+typedef FNMPWORKER *PFNMPWORKER;
+
+/**
+ * RTMpOn* argument packet used by the host specific callback
+ * wrapper functions.
+ */
+typedef struct RTMPARGS
+{
+ PFNMPWORKER pfnWorker;
+ void *pvUser1;
+ void *pvUser2;
+ RTCPUID idCpu;
+ RTCPUID idCpu2;
+ uint32_t volatile cHits;
+#ifdef RT_OS_WINDOWS
+ /** Turns out that KeFlushQueuedDpcs doesn't necessarily wait till all
+ * callbacks are done. So, do reference counting to make sure we don't free
+ * this structure befor all CPUs have completely handled their requests. */
+ int32_t volatile cRefs;
+#endif
+#ifdef RT_OS_LINUX
+ PRTCPUSET pWorkerSet;
+#endif
+} RTMPARGS;
+/** Pointer to a RTMpOn* argument packet. */
+typedef RTMPARGS *PRTMPARGS;
+
+/* Called from initterm-r0drv.cpp: */
+DECLHIDDEN(int) rtR0MpNotificationInit(void);
+DECLHIDDEN(void) rtR0MpNotificationTerm(void);
+
+/* The following is only relevant when using mpnotifcation-r0drv.cpp: */
+DECLHIDDEN(int) rtR0MpNotificationNativeInit(void);
+DECLHIDDEN(void) rtR0MpNotificationNativeTerm(void);
+DECLHIDDEN(void) rtMpNotificationDoCallbacks(RTMPEVENT enmEvent, RTCPUID idCpu);
+
+RT_C_DECLS_END
+
+#endif
+
--- /dev/null
+/* $Id: mpnotification-r0drv.c $ */
+/** @file
+ * IPRT - Multiprocessor, Ring-0 Driver, Event Notifications.
+ */
+
+/*
+ * Copyright (C) 2008-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/mp.h>
+#include "internal/iprt.h"
+
+#include <iprt/asm.h>
+#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
+# include <iprt/asm-amd64-x86.h>
+#endif
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/mem.h>
+#include <iprt/spinlock.h>
+#include <iprt/string.h>
+#include <iprt/thread.h>
+#include "r0drv/mp-r0drv.h"
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * Notification registration record tracking
+ * RTMpRegisterNotification() calls.
+ */
+typedef struct RTMPNOTIFYREG
+{
+ /** Pointer to the next record. */
+ struct RTMPNOTIFYREG * volatile pNext;
+ /** The callback. */
+ PFNRTMPNOTIFICATION pfnCallback;
+ /** The user argument. */
+ void *pvUser;
+ /** Bit mask indicating whether we've done this callback or not. */
+ uint8_t bmDone[sizeof(void *)];
+} RTMPNOTIFYREG;
+/** Pointer to a registration record. */
+typedef RTMPNOTIFYREG *PRTMPNOTIFYREG;
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/** The spinlock protecting the list. */
+static RTSPINLOCK volatile g_hRTMpNotifySpinLock = NIL_RTSPINLOCK;
+/** List of callbacks, in registration order. */
+static PRTMPNOTIFYREG volatile g_pRTMpCallbackHead = NULL;
+/** The current done bit. */
+static uint32_t volatile g_iRTMpDoneBit;
+/** The list generation.
+ * This is increased whenever the list has been modified. The callback routine
+ * make use of this to avoid having restart at the list head after each callback. */
+static uint32_t volatile g_iRTMpGeneration;
+
+
+
+
+/**
+ * This is called by the native code.
+ *
+ * @param idCpu The CPU id the event applies to.
+ * @param enmEvent The event.
+ */
+DECLHIDDEN(void) rtMpNotificationDoCallbacks(RTMPEVENT enmEvent, RTCPUID idCpu)
+{
+ PRTMPNOTIFYREG pCur;
+ RTSPINLOCK hSpinlock;
+
+ /*
+ * This is a little bit tricky as we cannot be holding the spinlock
+ * while calling the callback. This means that the list might change
+ * while we're walking it, and that multiple events might be running
+ * concurrently (depending on the OS).
+ *
+ * So, the first measure is to employ a 32-bitmask for each
+ * record where we'll use a bit that rotates for each call to
+ * this function to indicate which records that has been
+ * processed. This will take care of both changes to the list
+ * and a reasonable amount of concurrent events.
+ *
+ * In order to avoid having to restart the list walks for every
+ * callback we make, we'll make use a list generation number that is
+ * incremented everytime the list is changed. So, if it remains
+ * unchanged over a callback we can safely continue the iteration.
+ */
+ uint32_t iDone = ASMAtomicIncU32(&g_iRTMpDoneBit);
+ iDone %= RT_SIZEOFMEMB(RTMPNOTIFYREG, bmDone) * 8;
+
+ hSpinlock = g_hRTMpNotifySpinLock;
+ if (hSpinlock == NIL_RTSPINLOCK)
+ return;
+ RTSpinlockAcquire(hSpinlock);
+
+ /* Clear the bit. */
+ for (pCur = g_pRTMpCallbackHead; pCur; pCur = pCur->pNext)
+ ASMAtomicBitClear(&pCur->bmDone[0], iDone);
+
+ /* Iterate the records and perform the callbacks. */
+ do
+ {
+ uint32_t const iGeneration = ASMAtomicUoReadU32(&g_iRTMpGeneration);
+
+ pCur = g_pRTMpCallbackHead;
+ while (pCur)
+ {
+ if (!ASMAtomicBitTestAndSet(&pCur->bmDone[0], iDone))
+ {
+ PFNRTMPNOTIFICATION pfnCallback = pCur->pfnCallback;
+ void *pvUser = pCur->pvUser;
+ pCur = pCur->pNext;
+ RTSpinlockRelease(g_hRTMpNotifySpinLock);
+
+ pfnCallback(enmEvent, idCpu, pvUser);
+
+ /* carefully require the lock here, see RTR0MpNotificationTerm(). */
+ hSpinlock = g_hRTMpNotifySpinLock;
+ if (hSpinlock == NIL_RTSPINLOCK)
+ return;
+ RTSpinlockAcquire(hSpinlock);
+ if (ASMAtomicUoReadU32(&g_iRTMpGeneration) != iGeneration)
+ break;
+ }
+ else
+ pCur = pCur->pNext;
+ }
+ } while (pCur);
+
+ RTSpinlockRelease(hSpinlock);
+}
+
+
+
+RTDECL(int) RTMpNotificationRegister(PFNRTMPNOTIFICATION pfnCallback, void *pvUser)
+{
+ PRTMPNOTIFYREG pCur;
+ PRTMPNOTIFYREG pNew;
+
+ /*
+ * Validation.
+ */
+ AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
+ AssertReturn(g_hRTMpNotifySpinLock != NIL_RTSPINLOCK, VERR_WRONG_ORDER);
+ RT_ASSERT_PREEMPTIBLE();
+
+ RTSpinlockAcquire(g_hRTMpNotifySpinLock);
+ for (pCur = g_pRTMpCallbackHead; pCur; pCur = pCur->pNext)
+ if ( pCur->pvUser == pvUser
+ && pCur->pfnCallback == pfnCallback)
+ break;
+ RTSpinlockRelease(g_hRTMpNotifySpinLock);
+ AssertMsgReturn(!pCur, ("pCur=%p pfnCallback=%p pvUser=%p\n", pCur, pfnCallback, pvUser), VERR_ALREADY_EXISTS);
+
+ /*
+ * Allocate a new record and attempt to insert it.
+ */
+ pNew = (PRTMPNOTIFYREG)RTMemAlloc(sizeof(*pNew));
+ if (!pNew)
+ return VERR_NO_MEMORY;
+
+ pNew->pNext = NULL;
+ pNew->pfnCallback = pfnCallback;
+ pNew->pvUser = pvUser;
+ memset(&pNew->bmDone[0], 0xff, sizeof(pNew->bmDone));
+
+ RTSpinlockAcquire(g_hRTMpNotifySpinLock);
+
+ pCur = g_pRTMpCallbackHead;
+ if (!pCur)
+ g_pRTMpCallbackHead = pNew;
+ else
+ {
+ for (pCur = g_pRTMpCallbackHead; ; pCur = pCur->pNext)
+ if ( pCur->pvUser == pvUser
+ && pCur->pfnCallback == pfnCallback)
+ break;
+ else if (!pCur->pNext)
+ {
+ pCur->pNext = pNew;
+ pCur = NULL;
+ break;
+ }
+ }
+
+ ASMAtomicIncU32(&g_iRTMpGeneration);
+
+ RTSpinlockRelease(g_hRTMpNotifySpinLock);
+
+ /* duplicate? */
+ if (pCur)
+ {
+ RTMemFree(pCur);
+ AssertMsgFailedReturn(("pCur=%p pfnCallback=%p pvUser=%p\n", pCur, pfnCallback, pvUser), VERR_ALREADY_EXISTS);
+ }
+
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTMpNotificationRegister);
+
+
+RTDECL(int) RTMpNotificationDeregister(PFNRTMPNOTIFICATION pfnCallback, void *pvUser)
+{
+ PRTMPNOTIFYREG pPrev;
+ PRTMPNOTIFYREG pCur;
+
+ /*
+ * Validation.
+ */
+ AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
+ AssertReturn(g_hRTMpNotifySpinLock != NIL_RTSPINLOCK, VERR_WRONG_ORDER);
+ RT_ASSERT_INTS_ON();
+
+ /*
+ * Find and unlink the record from the list.
+ */
+ RTSpinlockAcquire(g_hRTMpNotifySpinLock);
+ pPrev = NULL;
+ for (pCur = g_pRTMpCallbackHead; pCur; pCur = pCur->pNext)
+ {
+ if ( pCur->pvUser == pvUser
+ && pCur->pfnCallback == pfnCallback)
+ break;
+ pPrev = pCur;
+ }
+ if (pCur)
+ {
+ if (pPrev)
+ pPrev->pNext = pCur->pNext;
+ else
+ g_pRTMpCallbackHead = pCur->pNext;
+ ASMAtomicIncU32(&g_iRTMpGeneration);
+ }
+ RTSpinlockRelease(g_hRTMpNotifySpinLock);
+
+ if (!pCur)
+ return VERR_NOT_FOUND;
+
+ /*
+ * Invalidate and free the record.
+ */
+ pCur->pNext = NULL;
+ pCur->pfnCallback = NULL;
+ RTMemFree(pCur);
+
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTMpNotificationDeregister);
+
+
+DECLHIDDEN(int) rtR0MpNotificationInit(void)
+{
+ int rc = RTSpinlockCreate((PRTSPINLOCK)&g_hRTMpNotifySpinLock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "RTR0Mp");
+ if (RT_SUCCESS(rc))
+ {
+ rc = rtR0MpNotificationNativeInit();
+ if (RT_SUCCESS(rc))
+ return rc;
+
+ RTSpinlockDestroy(g_hRTMpNotifySpinLock);
+ g_hRTMpNotifySpinLock = NIL_RTSPINLOCK;
+ }
+ return rc;
+}
+
+
+DECLHIDDEN(void) rtR0MpNotificationTerm(void)
+{
+ PRTMPNOTIFYREG pHead;
+ RTSPINLOCK hSpinlock = g_hRTMpNotifySpinLock;
+ AssertReturnVoid(hSpinlock != NIL_RTSPINLOCK);
+
+ rtR0MpNotificationNativeTerm();
+
+ /* pick up the list and the spinlock. */
+ RTSpinlockAcquire(hSpinlock);
+ ASMAtomicWriteHandle(&g_hRTMpNotifySpinLock, NIL_RTSPINLOCK);
+ pHead = g_pRTMpCallbackHead;
+ g_pRTMpCallbackHead = NULL;
+ ASMAtomicIncU32(&g_iRTMpGeneration);
+ RTSpinlockRelease(hSpinlock);
+
+ /* free the list. */
+ while (pHead)
+ {
+ PRTMPNOTIFYREG pFree = pHead;
+ pHead = pHead->pNext;
+
+ pFree->pNext = NULL;
+ pFree->pfnCallback = NULL;
+ RTMemFree(pFree);
+ }
+
+ RTSpinlockDestroy(hSpinlock);
+}
+
--- /dev/null
+/* $Id: power-r0drv.h $ */
+/** @file
+ * IPRT - Power Management, Ring-0 Driver, Internal Header.
+ */
+
+/*
+ * Copyright (C) 2008-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___r0drv_powermgt_r0drv_h
+#define ___r0drv_powermgt_r0drv_h
+
+#include <iprt/power.h>
+
+RT_C_DECLS_BEGIN
+
+/* Called from initterm-r0drv.cpp: */
+DECLHIDDEN(int) rtR0PowerNotificationInit(void);
+DECLHIDDEN(void) rtR0PowerNotificationTerm(void);
+
+RT_C_DECLS_END
+
+#endif
+
--- /dev/null
+/* $Id: powernotification-r0drv.c $ */
+/** @file
+ * IPRT - Power Management, Ring-0 Driver, Event Notifications.
+ */
+
+/*
+ * Copyright (C) 2008-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/power.h>
+#include "internal/iprt.h"
+
+#include <iprt/asm.h>
+#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
+# include <iprt/asm-amd64-x86.h>
+#endif
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/mem.h>
+#include <iprt/spinlock.h>
+#include <iprt/string.h>
+#include <iprt/thread.h>
+#include "r0drv/mp-r0drv.h"
+#include "r0drv/power-r0drv.h"
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * Notification registration record tracking
+ * RTPowerRegisterNotification() calls.
+ */
+typedef struct RTPOWERNOTIFYREG
+{
+ /** Pointer to the next record. */
+ struct RTPOWERNOTIFYREG * volatile pNext;
+ /** The callback. */
+ PFNRTPOWERNOTIFICATION pfnCallback;
+ /** The user argument. */
+ void *pvUser;
+ /** Bit mask indicating whether we've done this callback or not. */
+ uint8_t bmDone[sizeof(void *)];
+} RTPOWERNOTIFYREG;
+/** Pointer to a registration record. */
+typedef RTPOWERNOTIFYREG *PRTPOWERNOTIFYREG;
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/** The spinlock protecting the list. */
+static RTSPINLOCK volatile g_hRTPowerNotifySpinLock = NIL_RTSPINLOCK;
+/** List of callbacks, in registration order. */
+static PRTPOWERNOTIFYREG volatile g_pRTPowerCallbackHead = NULL;
+/** The current done bit. */
+static uint32_t volatile g_iRTPowerDoneBit;
+/** The list generation.
+ * This is increased whenever the list has been modified. The callback routine
+ * make use of this to avoid having restart at the list head after each callback. */
+static uint32_t volatile g_iRTPowerGeneration;
+
+
+
+
+RTDECL(int) RTPowerSignalEvent(RTPOWEREVENT enmEvent)
+{
+ PRTPOWERNOTIFYREG pCur;
+ RTSPINLOCK hSpinlock;
+
+ /*
+ * This is a little bit tricky as we cannot be holding the spinlock
+ * while calling the callback. This means that the list might change
+ * while we're walking it, and that multiple events might be running
+ * concurrently (depending on the OS).
+ *
+ * So, the first measure is to employ a 32-bitmask for each
+ * record where we'll use a bit that rotates for each call to
+ * this function to indicate which records that has been
+ * processed. This will take care of both changes to the list
+ * and a reasonable amount of concurrent events.
+ *
+ * In order to avoid having to restart the list walks for every
+ * callback we make, we'll make use a list generation number that is
+ * incremented everytime the list is changed. So, if it remains
+ * unchanged over a callback we can safely continue the iteration.
+ */
+ uint32_t iDone = ASMAtomicIncU32(&g_iRTPowerDoneBit);
+ iDone %= RT_SIZEOFMEMB(RTPOWERNOTIFYREG, bmDone) * 8;
+
+ hSpinlock = g_hRTPowerNotifySpinLock;
+ if (hSpinlock == NIL_RTSPINLOCK)
+ return VERR_ACCESS_DENIED;
+ RTSpinlockAcquire(hSpinlock);
+
+ /* Clear the bit. */
+ for (pCur = g_pRTPowerCallbackHead; pCur; pCur = pCur->pNext)
+ ASMAtomicBitClear(&pCur->bmDone[0], iDone);
+
+ /* Iterate the records and perform the callbacks. */
+ do
+ {
+ uint32_t const iGeneration = ASMAtomicUoReadU32(&g_iRTPowerGeneration);
+
+ pCur = g_pRTPowerCallbackHead;
+ while (pCur)
+ {
+ if (!ASMAtomicBitTestAndSet(&pCur->bmDone[0], iDone))
+ {
+ PFNRTPOWERNOTIFICATION pfnCallback = pCur->pfnCallback;
+ void *pvUser = pCur->pvUser;
+ pCur = pCur->pNext;
+ RTSpinlockRelease(g_hRTPowerNotifySpinLock);
+
+ pfnCallback(enmEvent, pvUser);
+
+ /* carefully require the lock here, see RTR0MpNotificationTerm(). */
+ hSpinlock = g_hRTPowerNotifySpinLock;
+ if (hSpinlock == NIL_RTSPINLOCK)
+ return VERR_ACCESS_DENIED;
+ RTSpinlockAcquire(hSpinlock);
+ if (ASMAtomicUoReadU32(&g_iRTPowerGeneration) != iGeneration)
+ break;
+ }
+ else
+ pCur = pCur->pNext;
+ }
+ } while (pCur);
+
+ RTSpinlockRelease(hSpinlock);
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTPowerSignalEvent);
+
+
+RTDECL(int) RTPowerNotificationRegister(PFNRTPOWERNOTIFICATION pfnCallback, void *pvUser)
+{
+ PRTPOWERNOTIFYREG pCur;
+ PRTPOWERNOTIFYREG pNew;
+
+ /*
+ * Validation.
+ */
+ AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
+ AssertReturn(g_hRTPowerNotifySpinLock != NIL_RTSPINLOCK, VERR_WRONG_ORDER);
+ RT_ASSERT_PREEMPTIBLE();
+
+ RTSpinlockAcquire(g_hRTPowerNotifySpinLock);
+ for (pCur = g_pRTPowerCallbackHead; pCur; pCur = pCur->pNext)
+ if ( pCur->pvUser == pvUser
+ && pCur->pfnCallback == pfnCallback)
+ break;
+ RTSpinlockRelease(g_hRTPowerNotifySpinLock);
+ AssertMsgReturn(!pCur, ("pCur=%p pfnCallback=%p pvUser=%p\n", pCur, pfnCallback, pvUser), VERR_ALREADY_EXISTS);
+
+ /*
+ * Allocate a new record and attempt to insert it.
+ */
+ pNew = (PRTPOWERNOTIFYREG)RTMemAlloc(sizeof(*pNew));
+ if (!pNew)
+ return VERR_NO_MEMORY;
+
+ pNew->pNext = NULL;
+ pNew->pfnCallback = pfnCallback;
+ pNew->pvUser = pvUser;
+ memset(&pNew->bmDone[0], 0xff, sizeof(pNew->bmDone));
+
+ RTSpinlockAcquire(g_hRTPowerNotifySpinLock);
+
+ pCur = g_pRTPowerCallbackHead;
+ if (!pCur)
+ g_pRTPowerCallbackHead = pNew;
+ else
+ {
+ for (pCur = g_pRTPowerCallbackHead; ; pCur = pCur->pNext)
+ if ( pCur->pvUser == pvUser
+ && pCur->pfnCallback == pfnCallback)
+ break;
+ else if (!pCur->pNext)
+ {
+ pCur->pNext = pNew;
+ pCur = NULL;
+ break;
+ }
+ }
+
+ ASMAtomicIncU32(&g_iRTPowerGeneration);
+
+ RTSpinlockRelease(g_hRTPowerNotifySpinLock);
+
+ /* duplicate? */
+ if (pCur)
+ {
+ RTMemFree(pCur);
+ AssertMsgFailedReturn(("pCur=%p pfnCallback=%p pvUser=%p\n", pCur, pfnCallback, pvUser), VERR_ALREADY_EXISTS);
+ }
+
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTPowerNotificationRegister);
+
+
+RTDECL(int) RTPowerNotificationDeregister(PFNRTPOWERNOTIFICATION pfnCallback, void *pvUser)
+{
+ PRTPOWERNOTIFYREG pPrev;
+ PRTPOWERNOTIFYREG pCur;
+
+ /*
+ * Validation.
+ */
+ AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
+ AssertReturn(g_hRTPowerNotifySpinLock != NIL_RTSPINLOCK, VERR_WRONG_ORDER);
+ RT_ASSERT_INTS_ON();
+
+ /*
+ * Find and unlink the record from the list.
+ */
+ RTSpinlockAcquire(g_hRTPowerNotifySpinLock);
+ pPrev = NULL;
+ for (pCur = g_pRTPowerCallbackHead; pCur; pCur = pCur->pNext)
+ {
+ if ( pCur->pvUser == pvUser
+ && pCur->pfnCallback == pfnCallback)
+ break;
+ pPrev = pCur;
+ }
+ if (pCur)
+ {
+ if (pPrev)
+ pPrev->pNext = pCur->pNext;
+ else
+ g_pRTPowerCallbackHead = pCur->pNext;
+ ASMAtomicIncU32(&g_iRTPowerGeneration);
+ }
+ RTSpinlockRelease(g_hRTPowerNotifySpinLock);
+
+ if (!pCur)
+ return VERR_NOT_FOUND;
+
+ /*
+ * Invalidate and free the record.
+ */
+ pCur->pNext = NULL;
+ pCur->pfnCallback = NULL;
+ RTMemFree(pCur);
+
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTPowerNotificationDeregister);
+
+
+DECLHIDDEN(int) rtR0PowerNotificationInit(void)
+{
+ int rc = RTSpinlockCreate((PRTSPINLOCK)&g_hRTPowerNotifySpinLock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "RTR0Power");
+ if (RT_SUCCESS(rc))
+ {
+ /** @todo OS specific init here */
+ return rc;
+#if 0
+ RTSpinlockDestroy(g_hRTPowerNotifySpinLock);
+ g_hRTPowerNotifySpinLock = NIL_RTSPINLOCK;
+#endif
+ }
+ return rc;
+}
+
+
+DECLHIDDEN(void) rtR0PowerNotificationTerm(void)
+{
+ PRTPOWERNOTIFYREG pHead;
+ RTSPINLOCK hSpinlock = g_hRTPowerNotifySpinLock;
+ AssertReturnVoid(hSpinlock != NIL_RTSPINLOCK);
+
+ /** @todo OS specific term here */
+
+ /* pick up the list and the spinlock. */
+ RTSpinlockAcquire(hSpinlock);
+ ASMAtomicWriteHandle(&g_hRTPowerNotifySpinLock, NIL_RTSPINLOCK);
+ pHead = g_pRTPowerCallbackHead;
+ g_pRTPowerCallbackHead = NULL;
+ ASMAtomicIncU32(&g_iRTPowerGeneration);
+ RTSpinlockRelease(hSpinlock);
+
+ /* free the list. */
+ while (pHead)
+ {
+ PRTPOWERNOTIFYREG pFree = pHead;
+ pHead = pHead->pNext;
+
+ pFree->pNext = NULL;
+ pFree->pfnCallback = NULL;
+ RTMemFree(pFree);
+ }
+
+ RTSpinlockDestroy(hSpinlock);
+}
+
--- /dev/null
+/* $Id: GenericRequest.cpp $ */
+/** @file
+ * VBoxGuestLibR0 - Generic VMMDev request management.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#include "VBGLInternal.h"
+#include <iprt/asm.h>
+#include <iprt/asm-amd64-x86.h>
+#include <iprt/assert.h>
+#include <iprt/string.h>
+
+
+DECLVBGL(int) VbglGRVerify(const VMMDevRequestHeader *pReq, size_t cbReq)
+{
+ size_t cbReqExpected;
+
+ if (RT_UNLIKELY(!pReq || cbReq < sizeof(VMMDevRequestHeader)))
+ {
+ dprintf(("VbglGRVerify: Invalid parameter: pReq = %p, cbReq = %zu\n", pReq, cbReq));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ if (RT_UNLIKELY(pReq->size > cbReq))
+ {
+ dprintf(("VbglGRVerify: request size %u > buffer size %zu\n", pReq->size, cbReq));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ /* The request size must correspond to the request type. */
+ cbReqExpected = vmmdevGetRequestSize(pReq->requestType);
+ if (RT_UNLIKELY(cbReq < cbReqExpected))
+ {
+ dprintf(("VbglGRVerify: buffer size %zu < expected size %zu\n", cbReq, cbReqExpected));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ if (cbReqExpected == cbReq)
+ {
+ /*
+ * This is most likely a fixed size request, and in this case the
+ * request size must be also equal to the expected size.
+ */
+ if (RT_UNLIKELY(pReq->size != cbReqExpected))
+ {
+ dprintf(("VbglGRVerify: request size %u != expected size %zu\n", pReq->size, cbReqExpected));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * This can be a variable size request. Check the request type and limit the size
+ * to VMMDEV_MAX_VMMDEVREQ_SIZE, which is max size supported by the host.
+ *
+ * Note: Keep this list sorted for easier human lookup!
+ */
+ if ( pReq->requestType == VMMDevReq_ChangeMemBalloon
+#ifdef VBOX_WITH_64_BITS_GUESTS
+ || pReq->requestType == VMMDevReq_HGCMCall32
+ || pReq->requestType == VMMDevReq_HGCMCall64
+#else
+ || pReq->requestType == VMMDevReq_HGCMCall
+#endif
+ || pReq->requestType == VMMDevReq_RegisterSharedModule
+ || pReq->requestType == VMMDevReq_ReportGuestUserState
+ || pReq->requestType == VMMDevReq_LogString
+ || pReq->requestType == VMMDevReq_SetPointerShape
+ || pReq->requestType == VMMDevReq_VideoSetVisibleRegion)
+ {
+ if (RT_UNLIKELY(cbReq > VMMDEV_MAX_VMMDEVREQ_SIZE))
+ {
+ dprintf(("VbglGRVerify: VMMDevReq_LogString: buffer size %zu too big\n", cbReq));
+ return VERR_BUFFER_OVERFLOW; /** @todo is this error code ok? */
+ }
+ }
+ else
+ {
+ dprintf(("VbglGRVerify: request size %u > buffer size %zu\n", pReq->size, cbReq));
+ return VERR_IO_BAD_LENGTH; /** @todo is this error code ok? */
+ }
+
+ return VINF_SUCCESS;
+}
+
+DECLVBGL(int) VbglGRAlloc(VMMDevRequestHeader **ppReq, size_t cbReq, VMMDevRequestType enmReqType)
+{
+ int rc = vbglR0Enter();
+ if (RT_SUCCESS(rc))
+ {
+ if ( ppReq
+ && cbReq >= sizeof(VMMDevRequestHeader)
+ && cbReq == (uint32_t)cbReq)
+ {
+ VMMDevRequestHeader *pReq = (VMMDevRequestHeader *)VbglPhysHeapAlloc((uint32_t)cbReq);
+ AssertMsgReturn(pReq, ("VbglGRAlloc: no memory (cbReq=%u)\n", cbReq), VERR_NO_MEMORY);
+ memset(pReq, 0xAA, cbReq);
+
+ pReq->size = (uint32_t)cbReq;
+ pReq->version = VMMDEV_REQUEST_HEADER_VERSION;
+ pReq->requestType = enmReqType;
+ pReq->rc = VERR_GENERAL_FAILURE;
+ pReq->reserved1 = 0;
+ pReq->reserved2 = 0;
+
+ *ppReq = pReq;
+ rc = VINF_SUCCESS;
+ }
+ else
+ {
+ dprintf(("VbglGRAlloc: Invalid parameter: ppReq=%p cbReq=%u\n", ppReq, cbReq));
+ rc = VERR_INVALID_PARAMETER;
+ }
+ }
+ return rc;
+}
+
+DECLVBGL(int) VbglGRPerform(VMMDevRequestHeader *pReq)
+{
+ int rc = vbglR0Enter();
+ if (RT_SUCCESS(rc))
+ {
+ if (pReq)
+ {
+ RTCCPHYS PhysAddr = VbglPhysHeapGetPhysAddr(pReq);
+ if ( PhysAddr != 0
+ && PhysAddr < _4G) /* Port IO is 32 bit. */
+ {
+ ASMOutU32(g_vbgldata.portVMMDev + VMMDEV_PORT_OFF_REQUEST, (uint32_t)PhysAddr);
+ /* Make the compiler aware that the host has changed memory. */
+ ASMCompilerBarrier();
+ rc = pReq->rc;
+ }
+ else
+ rc = VERR_VBGL_INVALID_ADDR;
+ }
+ else
+ rc = VERR_INVALID_PARAMETER;
+ }
+ return rc;
+}
+
+DECLVBGL(void) VbglGRFree(VMMDevRequestHeader *pReq)
+{
+ int rc = vbglR0Enter();
+ if (RT_SUCCESS(rc))
+ VbglPhysHeapFree(pReq);
+}
+
--- /dev/null
+/* $Id: HGCMInternal.cpp $ */
+/** @file
+ * VBoxGuestLib - Host-Guest Communication Manager internal functions, implemented by VBoxGuest
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+/* Entire file is ifdef'ed with VBGL_VBOXGUEST */
+#ifdef VBGL_VBOXGUEST
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_HGCM
+
+#include "VBGLInternal.h"
+#include <iprt/alloca.h>
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/mem.h>
+#include <iprt/memobj.h>
+#include <iprt/string.h>
+#include <iprt/thread.h>
+#include <iprt/time.h>
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/** The max parameter buffer size for a user request. */
+#define VBGLR0_MAX_HGCM_USER_PARM (24*_1M)
+/** The max parameter buffer size for a kernel request. */
+#define VBGLR0_MAX_HGCM_KERNEL_PARM (16*_1M)
+#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN)
+/** Linux needs to use bounce buffers since RTR0MemObjLockUser has unwanted
+ * side effects.
+ * Darwin 32bit & 64bit also needs this because of 4GB/4GB user/kernel space. */
+# define USE_BOUNCE_BUFFERS
+#endif
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * Lock info structure used by VbglR0HGCMInternalCall and its helpers.
+ */
+struct VbglR0ParmInfo
+{
+ uint32_t cLockBufs;
+ struct
+ {
+ uint32_t iParm;
+ RTR0MEMOBJ hObj;
+#ifdef USE_BOUNCE_BUFFERS
+ void *pvSmallBuf;
+#endif
+ } aLockBufs[10];
+};
+
+
+
+/* These functions can be only used by VBoxGuest. */
+
+DECLVBGL(int) VbglR0HGCMInternalConnect (VBoxGuestHGCMConnectInfo *pConnectInfo,
+ PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData)
+{
+ VMMDevHGCMConnect *pHGCMConnect;
+ int rc;
+
+ if (!pConnectInfo || !pfnAsyncCallback)
+ return VERR_INVALID_PARAMETER;
+
+ pHGCMConnect = NULL;
+
+ /* Allocate request */
+ rc = VbglGRAlloc ((VMMDevRequestHeader **)&pHGCMConnect, sizeof (VMMDevHGCMConnect), VMMDevReq_HGCMConnect);
+
+ if (RT_SUCCESS(rc))
+ {
+ /* Initialize request memory */
+ pHGCMConnect->header.fu32Flags = 0;
+
+ memcpy (&pHGCMConnect->loc, &pConnectInfo->Loc, sizeof (HGCMServiceLocation));
+ pHGCMConnect->u32ClientID = 0;
+
+ /* Issue request */
+ rc = VbglGRPerform (&pHGCMConnect->header.header);
+
+ if (RT_SUCCESS(rc))
+ {
+ /* Check if host decides to process the request asynchronously. */
+ if (rc == VINF_HGCM_ASYNC_EXECUTE)
+ {
+ /* Wait for request completion interrupt notification from host */
+ pfnAsyncCallback (&pHGCMConnect->header, pvAsyncData, u32AsyncData);
+ }
+
+ pConnectInfo->result = pHGCMConnect->header.result;
+
+ if (RT_SUCCESS (pConnectInfo->result))
+ pConnectInfo->u32ClientID = pHGCMConnect->u32ClientID;
+ }
+
+ VbglGRFree (&pHGCMConnect->header.header);
+ }
+
+ return rc;
+}
+
+
+DECLR0VBGL(int) VbglR0HGCMInternalDisconnect (VBoxGuestHGCMDisconnectInfo *pDisconnectInfo,
+ PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData)
+{
+ VMMDevHGCMDisconnect *pHGCMDisconnect;
+ int rc;
+
+ if (!pDisconnectInfo || !pfnAsyncCallback)
+ return VERR_INVALID_PARAMETER;
+
+ pHGCMDisconnect = NULL;
+
+ /* Allocate request */
+ rc = VbglGRAlloc ((VMMDevRequestHeader **)&pHGCMDisconnect, sizeof (VMMDevHGCMDisconnect), VMMDevReq_HGCMDisconnect);
+
+ if (RT_SUCCESS(rc))
+ {
+ /* Initialize request memory */
+ pHGCMDisconnect->header.fu32Flags = 0;
+
+ pHGCMDisconnect->u32ClientID = pDisconnectInfo->u32ClientID;
+
+ /* Issue request */
+ rc = VbglGRPerform (&pHGCMDisconnect->header.header);
+
+ if (RT_SUCCESS(rc))
+ {
+ /* Check if host decides to process the request asynchronously. */
+ if (rc == VINF_HGCM_ASYNC_EXECUTE)
+ {
+ /* Wait for request completion interrupt notification from host */
+ pfnAsyncCallback (&pHGCMDisconnect->header, pvAsyncData, u32AsyncData);
+ }
+
+ pDisconnectInfo->result = pHGCMDisconnect->header.result;
+ }
+
+ VbglGRFree (&pHGCMDisconnect->header.header);
+ }
+
+ return rc;
+}
+
+
+/**
+ * Preprocesses the HGCM call, validating and locking/buffering parameters.
+ *
+ * @returns VBox status code.
+ *
+ * @param pCallInfo The call info.
+ * @param cbCallInfo The size of the call info structure.
+ * @param fIsUser Is it a user request or kernel request.
+ * @param pcbExtra Where to return the extra request space needed for
+ * physical page lists.
+ */
+static int vbglR0HGCMInternalPreprocessCall(VBoxGuestHGCMCallInfo const *pCallInfo, uint32_t cbCallInfo,
+ bool fIsUser, struct VbglR0ParmInfo *pParmInfo, size_t *pcbExtra)
+{
+ HGCMFunctionParameter const *pSrcParm = VBOXGUEST_HGCM_CALL_PARMS(pCallInfo);
+ uint32_t cParms = pCallInfo->cParms;
+ uint32_t iParm;
+ uint32_t cb;
+
+ /*
+ * Lock down the any linear buffers so we can get their addresses
+ * and figure out how much extra storage we need for page lists.
+ *
+ * Note! With kernel mode users we can be assertive. For user mode users
+ * we should just (debug) log it and fail without any fanfare.
+ */
+ *pcbExtra = 0;
+ pParmInfo->cLockBufs = 0;
+ for (iParm = 0; iParm < cParms; iParm++, pSrcParm++)
+ {
+ switch (pSrcParm->type)
+ {
+ case VMMDevHGCMParmType_32bit:
+ Log4(("GstHGCMCall: parm=%u type=32bit: %#010x\n", iParm, pSrcParm->u.value32));
+ break;
+
+ case VMMDevHGCMParmType_64bit:
+ Log4(("GstHGCMCall: parm=%u type=64bit: %#018RX64\n", iParm, pSrcParm->u.value64));
+ break;
+
+ case VMMDevHGCMParmType_PageList:
+ if (fIsUser)
+ return VERR_INVALID_PARAMETER;
+ cb = pSrcParm->u.PageList.size;
+ if (cb)
+ {
+ uint32_t off = pSrcParm->u.PageList.offset;
+ HGCMPageListInfo *pPgLst;
+ uint32_t cPages;
+ uint32_t u32;
+
+ AssertMsgReturn(cb <= VBGLR0_MAX_HGCM_KERNEL_PARM, ("%#x > %#x\n", cb, VBGLR0_MAX_HGCM_KERNEL_PARM),
+ VERR_OUT_OF_RANGE);
+ AssertMsgReturn( off >= pCallInfo->cParms * sizeof(HGCMFunctionParameter)
+ && off <= cbCallInfo - sizeof(HGCMPageListInfo),
+ ("offset=%#x cParms=%#x cbCallInfo=%#x\n", off, pCallInfo->cParms, cbCallInfo),
+ VERR_INVALID_PARAMETER);
+
+ pPgLst = (HGCMPageListInfo *)((uint8_t *)pCallInfo + off);
+ cPages = pPgLst->cPages;
+ u32 = RT_OFFSETOF(HGCMPageListInfo, aPages[cPages]) + off;
+ AssertMsgReturn(u32 <= cbCallInfo,
+ ("u32=%#x (cPages=%#x offset=%#x) cbCallInfo=%#x\n", u32, cPages, off, cbCallInfo),
+ VERR_INVALID_PARAMETER);
+ AssertMsgReturn(pPgLst->offFirstPage < PAGE_SIZE, ("#x\n", pPgLst->offFirstPage), VERR_INVALID_PARAMETER);
+ u32 = RT_ALIGN_32(pPgLst->offFirstPage + cb, PAGE_SIZE) >> PAGE_SHIFT;
+ AssertMsgReturn(cPages == u32, ("cPages=%#x u32=%#x\n", cPages, u32), VERR_INVALID_PARAMETER);
+ AssertMsgReturn(VBOX_HGCM_F_PARM_ARE_VALID(pPgLst->flags), ("%#x\n", pPgLst->flags), VERR_INVALID_PARAMETER);
+ Log4(("GstHGCMCall: parm=%u type=pglst: cb=%#010x cPgs=%u offPg0=%#x flags=%#x\n",
+ iParm, cb, cPages, pPgLst->offFirstPage, pPgLst->flags));
+ u32 = cPages;
+ while (u32-- > 0)
+ {
+ Log4(("GstHGCMCall: pg#%u=%RHp\n", u32, pPgLst->aPages[u32]));
+ AssertMsgReturn(!(pPgLst->aPages[u32] & (PAGE_OFFSET_MASK | UINT64_C(0xfff0000000000000))),
+ ("pg#%u=%RHp\n", u32, pPgLst->aPages[u32]),
+ VERR_INVALID_PARAMETER);
+ }
+
+ *pcbExtra += RT_OFFSETOF(HGCMPageListInfo, aPages[pPgLst->cPages]);
+ }
+ else
+ Log4(("GstHGCMCall: parm=%u type=pglst: cb=0\n", iParm));
+ break;
+
+ case VMMDevHGCMParmType_LinAddr_Locked_In:
+ case VMMDevHGCMParmType_LinAddr_Locked_Out:
+ case VMMDevHGCMParmType_LinAddr_Locked:
+ if (fIsUser)
+ return VERR_INVALID_PARAMETER;
+ if (!VBGLR0_CAN_USE_PHYS_PAGE_LIST(/*a_fLocked =*/ true))
+ {
+ cb = pSrcParm->u.Pointer.size;
+ AssertMsgReturn(cb <= VBGLR0_MAX_HGCM_KERNEL_PARM, ("%#x > %#x\n", cb, VBGLR0_MAX_HGCM_KERNEL_PARM),
+ VERR_OUT_OF_RANGE);
+ if (cb != 0)
+ Log4(("GstHGCMCall: parm=%u type=%#x: cb=%#010x pv=%p\n",
+ iParm, pSrcParm->type, cb, pSrcParm->u.Pointer.u.linearAddr));
+ else
+ Log4(("GstHGCMCall: parm=%u type=%#x: cb=0\n", iParm, pSrcParm->type));
+ break;
+ }
+ /* fall thru */
+
+ case VMMDevHGCMParmType_LinAddr_In:
+ case VMMDevHGCMParmType_LinAddr_Out:
+ case VMMDevHGCMParmType_LinAddr:
+ cb = pSrcParm->u.Pointer.size;
+ if (cb != 0)
+ {
+#ifdef USE_BOUNCE_BUFFERS
+ void *pvSmallBuf = NULL;
+#endif
+ uint32_t iLockBuf = pParmInfo->cLockBufs;
+ RTR0MEMOBJ hObj;
+ int rc;
+ uint32_t fAccess = pSrcParm->type == VMMDevHGCMParmType_LinAddr_In
+ || pSrcParm->type == VMMDevHGCMParmType_LinAddr_Locked_In
+ ? RTMEM_PROT_READ
+ : RTMEM_PROT_READ | RTMEM_PROT_WRITE;
+
+ AssertReturn(iLockBuf < RT_ELEMENTS(pParmInfo->aLockBufs), VERR_INVALID_PARAMETER);
+ if (!fIsUser)
+ {
+ AssertMsgReturn(cb <= VBGLR0_MAX_HGCM_KERNEL_PARM, ("%#x > %#x\n", cb, VBGLR0_MAX_HGCM_KERNEL_PARM),
+ VERR_OUT_OF_RANGE);
+ rc = RTR0MemObjLockKernel(&hObj, (void *)pSrcParm->u.Pointer.u.linearAddr, cb, fAccess);
+ if (RT_FAILURE(rc))
+ {
+ Log(("GstHGCMCall: id=%#x fn=%u parm=%u RTR0MemObjLockKernel(,%p,%#x) -> %Rrc\n",
+ pCallInfo->u32ClientID, pCallInfo->u32Function, iParm, pSrcParm->u.Pointer.u.linearAddr, cb, rc));
+ return rc;
+ }
+ Log3(("GstHGCMCall: parm=%u type=%#x: cb=%#010x pv=%p locked kernel -> %p\n",
+ iParm, pSrcParm->type, cb, pSrcParm->u.Pointer.u.linearAddr, hObj));
+ }
+ else if (cb > VBGLR0_MAX_HGCM_USER_PARM)
+ {
+ Log(("GstHGCMCall: id=%#x fn=%u parm=%u pv=%p cb=%#x > %#x -> out of range\n",
+ pCallInfo->u32ClientID, pCallInfo->u32Function, iParm, pSrcParm->u.Pointer.u.linearAddr,
+ cb, VBGLR0_MAX_HGCM_USER_PARM));
+ return VERR_OUT_OF_RANGE;
+ }
+ else
+ {
+#ifndef USE_BOUNCE_BUFFERS
+ rc = RTR0MemObjLockUser(&hObj, (RTR3PTR)pSrcParm->u.Pointer.u.linearAddr, cb, fAccess, NIL_RTR0PROCESS);
+ if (RT_FAILURE(rc))
+ {
+ Log(("GstHGCMCall: id=%#x fn=%u parm=%u RTR0MemObjLockUser(,%p,%#x,nil) -> %Rrc\n",
+ pCallInfo->u32ClientID, pCallInfo->u32Function, iParm, pSrcParm->u.Pointer.u.linearAddr, cb, rc));
+ return rc;
+ }
+ Log3(("GstHGCMCall: parm=%u type=%#x: cb=%#010x pv=%p locked user -> %p\n",
+ iParm, pSrcParm->type, cb, pSrcParm->u.Pointer.u.linearAddr, hObj));
+
+#else /* USE_BOUNCE_BUFFERS */
+ /*
+ * This is a bit massive, but we don't want to waste a
+ * whole page for a 3 byte string buffer (guest props).
+ *
+ * The threshold is ASSUMING sizeof(RTMEMHDR) == 16 and
+ * the system is using some power of two allocator.
+ */
+ /** @todo A more efficient strategy would be to combine buffers. However it
+ * is probably going to be more massive than the current code, so
+ * it can wait till later. */
+ bool fCopyIn = pSrcParm->type != VMMDevHGCMParmType_LinAddr_Out
+ && pSrcParm->type != VMMDevHGCMParmType_LinAddr_Locked_Out;
+ if (cb <= PAGE_SIZE / 2 - 16)
+ {
+ pvSmallBuf = fCopyIn ? RTMemTmpAlloc(cb) : RTMemTmpAllocZ(cb);
+ if (RT_UNLIKELY(!pvSmallBuf))
+ return VERR_NO_MEMORY;
+ if (fCopyIn)
+ {
+ rc = RTR0MemUserCopyFrom(pvSmallBuf, pSrcParm->u.Pointer.u.linearAddr, cb);
+ if (RT_FAILURE(rc))
+ {
+ RTMemTmpFree(pvSmallBuf);
+ Log(("GstHGCMCall: id=%#x fn=%u parm=%u RTR0MemUserCopyFrom(,%p,%#x) -> %Rrc\n",
+ pCallInfo->u32ClientID, pCallInfo->u32Function, iParm,
+ pSrcParm->u.Pointer.u.linearAddr, cb, rc));
+ return rc;
+ }
+ }
+ rc = RTR0MemObjLockKernel(&hObj, pvSmallBuf, cb, fAccess);
+ if (RT_FAILURE(rc))
+ {
+ RTMemTmpFree(pvSmallBuf);
+ Log(("GstHGCMCall: RTR0MemObjLockKernel failed for small buffer: rc=%Rrc pvSmallBuf=%p cb=%#x\n",
+ rc, pvSmallBuf, cb));
+ return rc;
+ }
+ Log3(("GstHGCMCall: parm=%u type=%#x: cb=%#010x pv=%p small buffer %p -> %p\n",
+ iParm, pSrcParm->type, cb, pSrcParm->u.Pointer.u.linearAddr, pvSmallBuf, hObj));
+ }
+ else
+ {
+ rc = RTR0MemObjAllocPage(&hObj, cb, false /*fExecutable*/);
+ if (RT_FAILURE(rc))
+ return rc;
+ if (!fCopyIn)
+ memset(RTR0MemObjAddress(hObj), '\0', cb);
+ else
+ {
+ rc = RTR0MemUserCopyFrom(RTR0MemObjAddress(hObj), pSrcParm->u.Pointer.u.linearAddr, cb);
+ if (RT_FAILURE(rc))
+ {
+ RTR0MemObjFree(hObj, false /*fFreeMappings*/);
+ Log(("GstHGCMCall: id=%#x fn=%u parm=%u RTR0MemUserCopyFrom(,%p,%#x) -> %Rrc\n",
+ pCallInfo->u32ClientID, pCallInfo->u32Function, iParm,
+ pSrcParm->u.Pointer.u.linearAddr, cb, rc));
+ return rc;
+ }
+ }
+ Log3(("GstHGCMCall: parm=%u type=%#x: cb=%#010x pv=%p big buffer -> %p\n",
+ iParm, pSrcParm->type, cb, pSrcParm->u.Pointer.u.linearAddr, hObj));
+ }
+#endif /* USE_BOUNCE_BUFFERS */
+ }
+
+ pParmInfo->aLockBufs[iLockBuf].iParm = iParm;
+ pParmInfo->aLockBufs[iLockBuf].hObj = hObj;
+#ifdef USE_BOUNCE_BUFFERS
+ pParmInfo->aLockBufs[iLockBuf].pvSmallBuf = pvSmallBuf;
+#endif
+ pParmInfo->cLockBufs = iLockBuf + 1;
+
+ if (VBGLR0_CAN_USE_PHYS_PAGE_LIST(/*a_fLocked =*/ false))
+ {
+ size_t const cPages = RTR0MemObjSize(hObj) >> PAGE_SHIFT;
+ *pcbExtra += RT_OFFSETOF(HGCMPageListInfo, aPages[cPages]);
+ }
+ }
+ else
+ Log4(("GstHGCMCall: parm=%u type=%#x: cb=0\n", iParm, pSrcParm->type));
+ break;
+
+ default:
+ return VERR_INVALID_PARAMETER;
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Translates locked linear address to the normal type.
+ * The locked types are only for the guest side and not handled by the host.
+ *
+ * @returns normal linear address type.
+ * @param enmType The type.
+ */
+static HGCMFunctionParameterType vbglR0HGCMInternalConvertLinAddrType(HGCMFunctionParameterType enmType)
+{
+ switch (enmType)
+ {
+ case VMMDevHGCMParmType_LinAddr_Locked_In:
+ return VMMDevHGCMParmType_LinAddr_In;
+ case VMMDevHGCMParmType_LinAddr_Locked_Out:
+ return VMMDevHGCMParmType_LinAddr_Out;
+ case VMMDevHGCMParmType_LinAddr_Locked:
+ return VMMDevHGCMParmType_LinAddr;
+ default:
+ return enmType;
+ }
+}
+
+
+/**
+ * Translates linear address types to page list direction flags.
+ *
+ * @returns page list flags.
+ * @param enmType The type.
+ */
+static uint32_t vbglR0HGCMInternalLinAddrTypeToPageListFlags(HGCMFunctionParameterType enmType)
+{
+ switch (enmType)
+ {
+ case VMMDevHGCMParmType_LinAddr_In:
+ case VMMDevHGCMParmType_LinAddr_Locked_In:
+ return VBOX_HGCM_F_PARM_DIRECTION_TO_HOST;
+
+ case VMMDevHGCMParmType_LinAddr_Out:
+ case VMMDevHGCMParmType_LinAddr_Locked_Out:
+ return VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST;
+
+ default: AssertFailed();
+ case VMMDevHGCMParmType_LinAddr:
+ case VMMDevHGCMParmType_LinAddr_Locked:
+ return VBOX_HGCM_F_PARM_DIRECTION_BOTH;
+ }
+}
+
+
+/**
+ * Initializes the call request that we're sending to the host.
+ *
+ * @returns VBox status code.
+ *
+ * @param pCallInfo The call info.
+ * @param cbCallInfo The size of the call info structure.
+ * @param fIsUser Is it a user request or kernel request.
+ * @param pcbExtra Where to return the extra request space needed for
+ * physical page lists.
+ */
+static void vbglR0HGCMInternalInitCall(VMMDevHGCMCall *pHGCMCall, VBoxGuestHGCMCallInfo const *pCallInfo,
+ uint32_t cbCallInfo, bool fIsUser, struct VbglR0ParmInfo *pParmInfo)
+{
+ HGCMFunctionParameter const *pSrcParm = VBOXGUEST_HGCM_CALL_PARMS(pCallInfo);
+ HGCMFunctionParameter *pDstParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
+ uint32_t cParms = pCallInfo->cParms;
+ uint32_t offExtra = (uint32_t)((uintptr_t)(pDstParm + cParms) - (uintptr_t)pHGCMCall);
+ uint32_t iLockBuf = 0;
+ uint32_t iParm;
+ RT_NOREF1(cbCallInfo);
+#ifndef USE_BOUNCE_BUFFERS
+ RT_NOREF1(fIsUser);
+#endif
+
+ /*
+ * The call request headers.
+ */
+ pHGCMCall->header.fu32Flags = 0;
+ pHGCMCall->header.result = VINF_SUCCESS;
+
+ pHGCMCall->u32ClientID = pCallInfo->u32ClientID;
+ pHGCMCall->u32Function = pCallInfo->u32Function;
+ pHGCMCall->cParms = cParms;
+
+ /*
+ * The parameters.
+ */
+ for (iParm = 0; iParm < pCallInfo->cParms; iParm++, pSrcParm++, pDstParm++)
+ {
+ switch (pSrcParm->type)
+ {
+ case VMMDevHGCMParmType_32bit:
+ case VMMDevHGCMParmType_64bit:
+ *pDstParm = *pSrcParm;
+ break;
+
+ case VMMDevHGCMParmType_PageList:
+ pDstParm->type = VMMDevHGCMParmType_PageList;
+ pDstParm->u.PageList.size = pSrcParm->u.PageList.size;
+ if (pSrcParm->u.PageList.size)
+ {
+ HGCMPageListInfo const *pSrcPgLst = (HGCMPageListInfo *)((uint8_t *)pCallInfo + pSrcParm->u.PageList.offset);
+ HGCMPageListInfo *pDstPgLst = (HGCMPageListInfo *)((uint8_t *)pHGCMCall + offExtra);
+ uint32_t const cPages = pSrcPgLst->cPages;
+ uint32_t iPage;
+
+ pDstParm->u.PageList.offset = offExtra;
+ pDstPgLst->flags = pSrcPgLst->flags;
+ pDstPgLst->offFirstPage = pSrcPgLst->offFirstPage;
+ pDstPgLst->cPages = cPages;
+ for (iPage = 0; iPage < cPages; iPage++)
+ pDstPgLst->aPages[iPage] = pSrcPgLst->aPages[iPage];
+
+ offExtra += RT_OFFSETOF(HGCMPageListInfo, aPages[cPages]);
+ }
+ else
+ pDstParm->u.PageList.offset = 0;
+ break;
+
+ case VMMDevHGCMParmType_LinAddr_Locked_In:
+ case VMMDevHGCMParmType_LinAddr_Locked_Out:
+ case VMMDevHGCMParmType_LinAddr_Locked:
+ if (!VBGLR0_CAN_USE_PHYS_PAGE_LIST(/*a_fLocked =*/ true))
+ {
+ *pDstParm = *pSrcParm;
+ pDstParm->type = vbglR0HGCMInternalConvertLinAddrType(pSrcParm->type);
+ break;
+ }
+ /* fall thru */
+
+ case VMMDevHGCMParmType_LinAddr_In:
+ case VMMDevHGCMParmType_LinAddr_Out:
+ case VMMDevHGCMParmType_LinAddr:
+ if (pSrcParm->u.Pointer.size != 0)
+ {
+#ifdef USE_BOUNCE_BUFFERS
+ void *pvSmallBuf = pParmInfo->aLockBufs[iLockBuf].pvSmallBuf;
+#endif
+ RTR0MEMOBJ hObj = pParmInfo->aLockBufs[iLockBuf].hObj;
+ Assert(iParm == pParmInfo->aLockBufs[iLockBuf].iParm);
+
+ if (VBGLR0_CAN_USE_PHYS_PAGE_LIST(/*a_fLocked =*/ false))
+ {
+ HGCMPageListInfo *pDstPgLst = (HGCMPageListInfo *)((uint8_t *)pHGCMCall + offExtra);
+ size_t const cPages = RTR0MemObjSize(hObj) >> PAGE_SHIFT;
+ size_t iPage;
+
+ pDstParm->type = VMMDevHGCMParmType_PageList;
+ pDstParm->u.PageList.size = pSrcParm->u.Pointer.size;
+ pDstParm->u.PageList.offset = offExtra;
+ pDstPgLst->flags = vbglR0HGCMInternalLinAddrTypeToPageListFlags(pSrcParm->type);
+#ifdef USE_BOUNCE_BUFFERS
+ if (fIsUser)
+ pDstPgLst->offFirstPage = (uintptr_t)pvSmallBuf & PAGE_OFFSET_MASK;
+ else
+#endif
+ pDstPgLst->offFirstPage = pSrcParm->u.Pointer.u.linearAddr & PAGE_OFFSET_MASK;
+ pDstPgLst->cPages = (uint32_t)cPages; Assert(pDstPgLst->cPages == cPages);
+ for (iPage = 0; iPage < cPages; iPage++)
+ {
+ pDstPgLst->aPages[iPage] = RTR0MemObjGetPagePhysAddr(hObj, iPage);
+ Assert(pDstPgLst->aPages[iPage] != NIL_RTHCPHYS);
+ }
+
+ offExtra += RT_OFFSETOF(HGCMPageListInfo, aPages[cPages]);
+ }
+ else
+ {
+ pDstParm->type = vbglR0HGCMInternalConvertLinAddrType(pSrcParm->type);
+ pDstParm->u.Pointer.size = pSrcParm->u.Pointer.size;
+#ifdef USE_BOUNCE_BUFFERS
+ if (fIsUser)
+ pDstParm->u.Pointer.u.linearAddr = pvSmallBuf
+ ? (uintptr_t)pvSmallBuf
+ : (uintptr_t)RTR0MemObjAddress(hObj);
+ else
+#endif
+ pDstParm->u.Pointer.u.linearAddr = pSrcParm->u.Pointer.u.linearAddr;
+ }
+ iLockBuf++;
+ }
+ else
+ {
+ pDstParm->type = vbglR0HGCMInternalConvertLinAddrType(pSrcParm->type);
+ pDstParm->u.Pointer.size = 0;
+ pDstParm->u.Pointer.u.linearAddr = 0;
+ }
+ break;
+
+ default:
+ AssertFailed();
+ pDstParm->type = VMMDevHGCMParmType_Invalid;
+ break;
+ }
+ }
+}
+
+
+/**
+ * Performs the call and completion wait.
+ *
+ * @returns VBox status code of this operation, not necessarily the call.
+ *
+ * @param pHGCMCall The HGCM call info.
+ * @param pfnAsyncCallback The async callback that will wait for the call
+ * to complete.
+ * @param pvAsyncData Argument for the callback.
+ * @param u32AsyncData Argument for the callback.
+ * @param pfLeakIt Where to return the leak it / free it,
+ * indicator. Cancellation fun.
+ */
+static int vbglR0HGCMInternalDoCall(VMMDevHGCMCall *pHGCMCall, PFNVBGLHGCMCALLBACK pfnAsyncCallback,
+ void *pvAsyncData, uint32_t u32AsyncData, bool *pfLeakIt)
+{
+ int rc;
+
+ Log(("calling VbglGRPerform\n"));
+ rc = VbglGRPerform(&pHGCMCall->header.header);
+ Log(("VbglGRPerform rc = %Rrc (header rc=%d)\n", rc, pHGCMCall->header.result));
+
+ /*
+ * If the call failed, but as a result of the request itself, then pretend
+ * success. Upper layers will interpret the result code in the packet.
+ */
+ if ( RT_FAILURE(rc)
+ && rc == pHGCMCall->header.result)
+ {
+ Assert(pHGCMCall->header.fu32Flags & VBOX_HGCM_REQ_DONE);
+ rc = VINF_SUCCESS;
+ }
+
+ /*
+ * Check if host decides to process the request asynchronously,
+ * if so, we wait for it to complete using the caller supplied callback.
+ */
+ *pfLeakIt = false;
+ if (rc == VINF_HGCM_ASYNC_EXECUTE)
+ {
+ Log(("Processing HGCM call asynchronously\n"));
+ rc = pfnAsyncCallback(&pHGCMCall->header, pvAsyncData, u32AsyncData);
+ if (pHGCMCall->header.fu32Flags & VBOX_HGCM_REQ_DONE)
+ {
+ Assert(!(pHGCMCall->header.fu32Flags & VBOX_HGCM_REQ_CANCELLED));
+ rc = VINF_SUCCESS;
+ }
+ else
+ {
+ /*
+ * The request didn't complete in time or the call was interrupted,
+ * the RC from the callback indicates which. Try cancel the request.
+ *
+ * This is a bit messy because we're racing request completion. Sorry.
+ */
+ /** @todo It would be nice if we could use the waiter callback to do further
+ * waiting in case of a completion race. If it wasn't for WINNT having its own
+ * version of all that stuff, I would've done it already. */
+ VMMDevHGCMCancel2 *pCancelReq;
+ int rc2 = VbglGRAlloc((VMMDevRequestHeader **)&pCancelReq, sizeof(*pCancelReq), VMMDevReq_HGCMCancel2);
+ if (RT_SUCCESS(rc2))
+ {
+ pCancelReq->physReqToCancel = VbglPhysHeapGetPhysAddr(pHGCMCall);
+ rc2 = VbglGRPerform(&pCancelReq->header);
+ VbglGRFree(&pCancelReq->header);
+ }
+#if 1 /** @todo ADDVER: Remove this on next minor version change. */
+ if (rc2 == VERR_NOT_IMPLEMENTED)
+ {
+ /* host is too old, or we're out of heap. */
+ pHGCMCall->header.fu32Flags |= VBOX_HGCM_REQ_CANCELLED;
+ pHGCMCall->header.header.requestType = VMMDevReq_HGCMCancel;
+ rc2 = VbglGRPerform(&pHGCMCall->header.header);
+ if (rc2 == VERR_INVALID_PARAMETER)
+ rc2 = VERR_NOT_FOUND;
+ else if (RT_SUCCESS(rc))
+ RTThreadSleep(1);
+ }
+#endif
+ if (RT_SUCCESS(rc)) rc = VERR_INTERRUPTED; /** @todo weed this out from the WINNT VBoxGuest code. */
+ if (RT_SUCCESS(rc2))
+ {
+ Log(("vbglR0HGCMInternalDoCall: successfully cancelled\n"));
+ pHGCMCall->header.fu32Flags |= VBOX_HGCM_REQ_CANCELLED;
+ }
+ else
+ {
+ /*
+ * Wait for a bit while the host (hopefully) completes it.
+ */
+ uint64_t u64Start = RTTimeSystemMilliTS();
+ uint32_t cMilliesToWait = rc2 == VERR_NOT_FOUND || rc2 == VERR_SEM_DESTROYED ? 500 : 2000;
+ uint64_t cElapsed = 0;
+ if (rc2 != VERR_NOT_FOUND)
+ {
+ static unsigned s_cErrors = 0;
+ if (s_cErrors++ < 32)
+ LogRel(("vbglR0HGCMInternalDoCall: Failed to cancel the HGCM call on %Rrc: rc2=%Rrc\n", rc, rc2));
+ }
+ else
+ Log(("vbglR0HGCMInternalDoCall: Cancel race rc=%Rrc rc2=%Rrc\n", rc, rc2));
+
+ do
+ {
+ ASMCompilerBarrier(); /* paranoia */
+ if (pHGCMCall->header.fu32Flags & VBOX_HGCM_REQ_DONE)
+ break;
+ RTThreadSleep(1);
+ cElapsed = RTTimeSystemMilliTS() - u64Start;
+ } while (cElapsed < cMilliesToWait);
+
+ ASMCompilerBarrier(); /* paranoia^2 */
+ if (pHGCMCall->header.fu32Flags & VBOX_HGCM_REQ_DONE)
+ rc = VINF_SUCCESS;
+ else
+ {
+ LogRel(("vbglR0HGCMInternalDoCall: Leaking %u bytes. Pending call to %u with %u parms. (rc2=%Rrc)\n",
+ pHGCMCall->header.header.size, pHGCMCall->u32Function, pHGCMCall->cParms, rc2));
+ *pfLeakIt = true;
+ }
+ Log(("vbglR0HGCMInternalDoCall: Cancel race ended with rc=%Rrc (rc2=%Rrc) after %llu ms\n", rc, rc2, cElapsed));
+ }
+ }
+ }
+
+ Log(("GstHGCMCall: rc=%Rrc result=%Rrc fu32Flags=%#x fLeakIt=%d\n",
+ rc, pHGCMCall->header.result, pHGCMCall->header.fu32Flags, *pfLeakIt));
+ return rc;
+}
+
+
+/**
+ * Copies the result of the call back to the caller info structure and user
+ * buffers (if using bounce buffers).
+ *
+ * @returns rc, unless RTR0MemUserCopyTo fails.
+ * @param pCallInfo Call info structure to update.
+ * @param pHGCMCall HGCM call request.
+ * @param pParmInfo Parameter locking/buffering info.
+ * @param fIsUser Is it a user (true) or kernel request.
+ * @param rc The current result code. Passed along to
+ * preserve informational status codes.
+ */
+static int vbglR0HGCMInternalCopyBackResult(VBoxGuestHGCMCallInfo *pCallInfo, VMMDevHGCMCall const *pHGCMCall,
+ struct VbglR0ParmInfo *pParmInfo, bool fIsUser, int rc)
+{
+ HGCMFunctionParameter const *pSrcParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
+ HGCMFunctionParameter *pDstParm = VBOXGUEST_HGCM_CALL_PARMS(pCallInfo);
+ uint32_t cParms = pCallInfo->cParms;
+#ifdef USE_BOUNCE_BUFFERS
+ uint32_t iLockBuf = 0;
+#endif
+ uint32_t iParm;
+ RT_NOREF1(pParmInfo);
+#ifndef USE_BOUNCE_BUFFERS
+ RT_NOREF1(fIsUser);
+#endif
+
+ /*
+ * The call result.
+ */
+ pCallInfo->result = pHGCMCall->header.result;
+
+ /*
+ * Copy back parameters.
+ */
+ for (iParm = 0; iParm < cParms; iParm++, pSrcParm++, pDstParm++)
+ {
+ switch (pDstParm->type)
+ {
+ case VMMDevHGCMParmType_32bit:
+ case VMMDevHGCMParmType_64bit:
+ *pDstParm = *pSrcParm;
+ break;
+
+ case VMMDevHGCMParmType_PageList:
+ pDstParm->u.PageList.size = pSrcParm->u.PageList.size;
+ break;
+
+ case VMMDevHGCMParmType_LinAddr_Locked_In:
+ case VMMDevHGCMParmType_LinAddr_In:
+#ifdef USE_BOUNCE_BUFFERS
+ if ( fIsUser
+ && iLockBuf < pParmInfo->cLockBufs
+ && iParm == pParmInfo->aLockBufs[iLockBuf].iParm)
+ iLockBuf++;
+#endif
+ pDstParm->u.Pointer.size = pSrcParm->u.Pointer.size;
+ break;
+
+ case VMMDevHGCMParmType_LinAddr_Locked_Out:
+ case VMMDevHGCMParmType_LinAddr_Locked:
+ if (!VBGLR0_CAN_USE_PHYS_PAGE_LIST(/*a_fLocked =*/ true))
+ {
+ pDstParm->u.Pointer.size = pSrcParm->u.Pointer.size;
+ break;
+ }
+ /* fall thru */
+
+ case VMMDevHGCMParmType_LinAddr_Out:
+ case VMMDevHGCMParmType_LinAddr:
+ {
+#ifdef USE_BOUNCE_BUFFERS
+ if (fIsUser)
+ {
+ size_t cbOut = RT_MIN(pSrcParm->u.Pointer.size, pDstParm->u.Pointer.size);
+ if (cbOut)
+ {
+ int rc2;
+ Assert(pParmInfo->aLockBufs[iLockBuf].iParm == iParm);
+ rc2 = RTR0MemUserCopyTo((RTR3PTR)pDstParm->u.Pointer.u.linearAddr,
+ pParmInfo->aLockBufs[iLockBuf].pvSmallBuf
+ ? pParmInfo->aLockBufs[iLockBuf].pvSmallBuf
+ : RTR0MemObjAddress(pParmInfo->aLockBufs[iLockBuf].hObj),
+ cbOut);
+ if (RT_FAILURE(rc2))
+ return rc2;
+ iLockBuf++;
+ }
+ else if ( iLockBuf < pParmInfo->cLockBufs
+ && iParm == pParmInfo->aLockBufs[iLockBuf].iParm)
+ iLockBuf++;
+ }
+#endif
+ pDstParm->u.Pointer.size = pSrcParm->u.Pointer.size;
+ break;
+ }
+
+ default:
+ AssertFailed();
+ rc = VERR_INTERNAL_ERROR_4;
+ break;
+ }
+ }
+
+#ifdef USE_BOUNCE_BUFFERS
+ Assert(!fIsUser || pParmInfo->cLockBufs == iLockBuf);
+#endif
+ return rc;
+}
+
+
+DECLR0VBGL(int) VbglR0HGCMInternalCall(VBoxGuestHGCMCallInfo *pCallInfo, uint32_t cbCallInfo, uint32_t fFlags,
+ PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData)
+{
+ bool fIsUser = (fFlags & VBGLR0_HGCMCALL_F_MODE_MASK) == VBGLR0_HGCMCALL_F_USER;
+ struct VbglR0ParmInfo ParmInfo;
+ size_t cbExtra;
+ int rc;
+
+ /*
+ * Basic validation.
+ */
+ AssertMsgReturn( !pCallInfo
+ || !pfnAsyncCallback
+ || pCallInfo->cParms > VBOX_HGCM_MAX_PARMS
+ || !(fFlags & ~VBGLR0_HGCMCALL_F_MODE_MASK),
+ ("pCallInfo=%p pfnAsyncCallback=%p fFlags=%#x\n", pCallInfo, pfnAsyncCallback, fFlags),
+ VERR_INVALID_PARAMETER);
+ AssertReturn( cbCallInfo >= sizeof(VBoxGuestHGCMCallInfo)
+ || cbCallInfo >= pCallInfo->cParms * sizeof(HGCMFunctionParameter),
+ VERR_INVALID_PARAMETER);
+
+ Log(("GstHGCMCall: u32ClientID=%#x u32Function=%u cParms=%u cbCallInfo=%#x fFlags=%#x\n",
+ pCallInfo->u32ClientID, pCallInfo->u32ClientID, pCallInfo->u32Function, pCallInfo->cParms, cbCallInfo, fFlags));
+
+ /*
+ * Validate, lock and buffer the parameters for the call.
+ * This will calculate the amount of extra space for physical page list.
+ */
+ rc = vbglR0HGCMInternalPreprocessCall(pCallInfo, cbCallInfo, fIsUser, &ParmInfo, &cbExtra);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Allocate the request buffer and recreate the call request.
+ */
+ VMMDevHGCMCall *pHGCMCall;
+ rc = VbglGRAlloc((VMMDevRequestHeader **)&pHGCMCall,
+ sizeof(VMMDevHGCMCall) + pCallInfo->cParms * sizeof(HGCMFunctionParameter) + cbExtra,
+ VMMDevReq_HGCMCall);
+ if (RT_SUCCESS(rc))
+ {
+ bool fLeakIt;
+ vbglR0HGCMInternalInitCall(pHGCMCall, pCallInfo, cbCallInfo, fIsUser, &ParmInfo);
+
+ /*
+ * Perform the call.
+ */
+ rc = vbglR0HGCMInternalDoCall(pHGCMCall, pfnAsyncCallback, pvAsyncData, u32AsyncData, &fLeakIt);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Copy back the result (parameters and buffers that changed).
+ */
+ rc = vbglR0HGCMInternalCopyBackResult(pCallInfo, pHGCMCall, &ParmInfo, fIsUser, rc);
+ }
+ else
+ {
+ if ( rc != VERR_INTERRUPTED
+ && rc != VERR_TIMEOUT)
+ {
+ static unsigned s_cErrors = 0;
+ if (s_cErrors++ < 32)
+ LogRel(("VbglR0HGCMInternalCall: vbglR0HGCMInternalDoCall failed. rc=%Rrc\n", rc));
+ }
+ }
+
+ if (!fLeakIt)
+ VbglGRFree(&pHGCMCall->header.header);
+ }
+ }
+ else
+ LogRel(("VbglR0HGCMInternalCall: vbglR0HGCMInternalPreprocessCall failed. rc=%Rrc\n", rc));
+
+ /*
+ * Release locks and free bounce buffers.
+ */
+ if (ParmInfo.cLockBufs)
+ while (ParmInfo.cLockBufs-- > 0)
+ {
+ RTR0MemObjFree(ParmInfo.aLockBufs[ParmInfo.cLockBufs].hObj, false /*fFreeMappings*/);
+#ifdef USE_BOUNCE_BUFFERS
+ RTMemTmpFree(ParmInfo.aLockBufs[ParmInfo.cLockBufs].pvSmallBuf);
+#endif
+ }
+
+ return rc;
+}
+
+
+#if ARCH_BITS == 64
+DECLR0VBGL(int) VbglR0HGCMInternalCall32(VBoxGuestHGCMCallInfo *pCallInfo, uint32_t cbCallInfo, uint32_t fFlags,
+ PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData)
+{
+ VBoxGuestHGCMCallInfo *pCallInfo64 = NULL;
+ HGCMFunctionParameter *pParm64 = NULL;
+ HGCMFunctionParameter32 *pParm32 = NULL;
+ uint32_t cParms = 0;
+ uint32_t iParm = 0;
+ int rc = VINF_SUCCESS;
+
+ /*
+ * Input validation.
+ */
+ AssertMsgReturn( !pCallInfo
+ || !pfnAsyncCallback
+ || pCallInfo->cParms > VBOX_HGCM_MAX_PARMS
+ || !(fFlags & ~VBGLR0_HGCMCALL_F_MODE_MASK),
+ ("pCallInfo=%p pfnAsyncCallback=%p fFlags=%#x\n", pCallInfo, pfnAsyncCallback, fFlags),
+ VERR_INVALID_PARAMETER);
+ AssertReturn( cbCallInfo >= sizeof(VBoxGuestHGCMCallInfo)
+ || cbCallInfo >= pCallInfo->cParms * sizeof(HGCMFunctionParameter32),
+ VERR_INVALID_PARAMETER);
+
+ /* This Assert does not work on Solaris/Windows 64/32 mixed mode, not sure why, skipping for now */
+#if !defined(RT_OS_SOLARIS) && !defined(RT_OS_WINDOWS)
+ AssertReturn((fFlags & VBGLR0_HGCMCALL_F_MODE_MASK) == VBGLR0_HGCMCALL_F_KERNEL, VERR_WRONG_ORDER);
+#endif
+
+ cParms = pCallInfo->cParms;
+ Log(("VbglR0HGCMInternalCall32: cParms=%d, u32Function=%d, fFlags=%#x\n", cParms, pCallInfo->u32Function, fFlags));
+
+ /*
+ * The simple approach, allocate a temporary request and convert the parameters.
+ */
+ pCallInfo64 = (VBoxGuestHGCMCallInfo *)RTMemTmpAllocZ(sizeof(*pCallInfo64) + cParms * sizeof(HGCMFunctionParameter));
+ if (!pCallInfo64)
+ return VERR_NO_TMP_MEMORY;
+
+ *pCallInfo64 = *pCallInfo;
+ pParm32 = VBOXGUEST_HGCM_CALL_PARMS32(pCallInfo);
+ pParm64 = VBOXGUEST_HGCM_CALL_PARMS(pCallInfo64);
+ for (iParm = 0; iParm < cParms; iParm++, pParm32++, pParm64++)
+ {
+ switch (pParm32->type)
+ {
+ case VMMDevHGCMParmType_32bit:
+ pParm64->type = VMMDevHGCMParmType_32bit;
+ pParm64->u.value32 = pParm32->u.value32;
+ break;
+
+ case VMMDevHGCMParmType_64bit:
+ pParm64->type = VMMDevHGCMParmType_64bit;
+ pParm64->u.value64 = pParm32->u.value64;
+ break;
+
+ case VMMDevHGCMParmType_LinAddr_Out:
+ case VMMDevHGCMParmType_LinAddr:
+ case VMMDevHGCMParmType_LinAddr_In:
+ pParm64->type = pParm32->type;
+ pParm64->u.Pointer.size = pParm32->u.Pointer.size;
+ pParm64->u.Pointer.u.linearAddr = pParm32->u.Pointer.u.linearAddr;
+ break;
+
+ default:
+ rc = VERR_INVALID_PARAMETER;
+ LogRel(("VbglR0HGCMInternalCall32: pParm32 type %#x invalid.\n", pParm32->type));
+ break;
+ }
+ if (RT_FAILURE(rc))
+ break;
+ }
+ if (RT_SUCCESS(rc))
+ {
+ rc = VbglR0HGCMInternalCall(pCallInfo64, sizeof(*pCallInfo64) + cParms * sizeof(HGCMFunctionParameter), fFlags,
+ pfnAsyncCallback, pvAsyncData, u32AsyncData);
+
+ if (RT_SUCCESS(rc))
+ {
+ *pCallInfo = *pCallInfo64;
+
+ /*
+ * Copy back.
+ */
+ pParm32 = VBOXGUEST_HGCM_CALL_PARMS32(pCallInfo);
+ pParm64 = VBOXGUEST_HGCM_CALL_PARMS(pCallInfo64);
+ for (iParm = 0; iParm < cParms; iParm++, pParm32++, pParm64++)
+ {
+ switch (pParm64->type)
+ {
+ case VMMDevHGCMParmType_32bit:
+ pParm32->u.value32 = pParm64->u.value32;
+ break;
+
+ case VMMDevHGCMParmType_64bit:
+ pParm32->u.value64 = pParm64->u.value64;
+ break;
+
+ case VMMDevHGCMParmType_LinAddr_Out:
+ case VMMDevHGCMParmType_LinAddr:
+ case VMMDevHGCMParmType_LinAddr_In:
+ pParm32->u.Pointer.size = pParm64->u.Pointer.size;
+ break;
+
+ default:
+ LogRel(("VbglR0HGCMInternalCall32: failed invalid pParm32 type %d\n", pParm32->type));
+ rc = VERR_INTERNAL_ERROR_3;
+ break;
+ }
+ }
+ }
+ else
+ {
+ static unsigned s_cErrors = 0;
+ if (s_cErrors++ < 32)
+ LogRel(("VbglR0HGCMInternalCall32: VbglR0HGCMInternalCall failed. rc=%Rrc\n", rc));
+ }
+ }
+ else
+ {
+ static unsigned s_cErrors = 0;
+ if (s_cErrors++ < 32)
+ LogRel(("VbglR0HGCMInternalCall32: failed. rc=%Rrc\n", rc));
+ }
+
+ RTMemTmpFree(pCallInfo64);
+ return rc;
+}
+#endif /* ARCH_BITS == 64 */
+
+#endif /* VBGL_VBOXGUEST */
+
--- /dev/null
+/* $Id: Init.cpp $ */
+/** @file
+ * VBoxGuestLibR0 - Library initialization.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define VBGL_DECL_DATA
+#include "VBGLInternal.h"
+
+#include <iprt/string.h>
+#include <iprt/assert.h>
+#include <iprt/semaphore.h>
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/** The global VBGL instance data. */
+VBGLDATA g_vbgldata;
+
+/**
+ * Used by vbglQueryDriverInfo and VbglInit to try get the host feature mask and
+ * version information (g_vbgldata::hostVersion).
+ *
+ * This was first implemented by the host in 3.1 and we quietly ignore failures
+ * for that reason.
+ */
+static void vbglR0QueryHostVersion (void)
+{
+ VMMDevReqHostVersion *pReq;
+
+ int rc = VbglGRAlloc ((VMMDevRequestHeader **) &pReq, sizeof (*pReq), VMMDevReq_GetHostVersion);
+
+ if (RT_SUCCESS (rc))
+ {
+ rc = VbglGRPerform (&pReq->header);
+
+ if (RT_SUCCESS (rc))
+ {
+ g_vbgldata.hostVersion = *pReq;
+ Log (("vbglR0QueryHostVersion: %u.%u.%ur%u %#x\n",
+ pReq->major, pReq->minor, pReq->build, pReq->revision, pReq->features));
+ }
+
+ VbglGRFree (&pReq->header);
+ }
+}
+
+#ifndef VBGL_VBOXGUEST
+/**
+ * The guest library uses lazy initialization for VMMDev port and memory,
+ * because these values are provided by the VBoxGuest driver and it might
+ * be loaded later than other drivers.
+ *
+ * The VbglEnter checks the current library status, tries to retrieve these
+ * values and fails if they are unavailable.
+ *
+ */
+static void vbglQueryDriverInfo (void)
+{
+ int rc = VINF_SUCCESS;
+
+ rc = RTSemMutexRequest(g_vbgldata.mutexDriverInit, RT_INDEFINITE_WAIT);
+
+ if (RT_FAILURE(rc))
+ return;
+
+ if (g_vbgldata.status == VbglStatusReady)
+ {
+ RTSemMutexRelease(g_vbgldata.mutexDriverInit);
+ return;
+ }
+
+ rc = vbglDriverOpen(&g_vbgldata.driver);
+
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Try query the port info.
+ */
+ VBoxGuestPortInfo port;
+
+ rc = vbglDriverIOCtl (&g_vbgldata.driver,
+ VBOXGUEST_IOCTL_GETVMMDEVPORT, &port,
+ sizeof (port));
+
+ if (RT_SUCCESS (rc))
+ {
+ dprintf (("port = 0x%04X, mem = %p\n", port.portAddress, port.pVMMDevMemory));
+
+ g_vbgldata.portVMMDev = (RTIOPORT)port.portAddress;
+ g_vbgldata.pVMMDevMemory = port.pVMMDevMemory;
+
+ g_vbgldata.status = VbglStatusReady;
+
+ vbglR0QueryHostVersion();
+ }
+ }
+ RTSemMutexRelease(g_vbgldata.mutexDriverInit);
+ dprintf (("vbglQueryDriverInfo rc = %d\n", rc));
+}
+#endif /* !VBGL_VBOXGUEST */
+
+/**
+ * Checks if VBGL has been initialized.
+ *
+ * The client library, this will lazily complete the initialization.
+ *
+ * @return VINF_SUCCESS or VERR_VBGL_NOT_INITIALIZED.
+ */
+int vbglR0Enter (void)
+{
+ int rc;
+
+#ifndef VBGL_VBOXGUEST
+ if (g_vbgldata.status == VbglStatusInitializing)
+ {
+ vbglQueryDriverInfo ();
+ }
+#endif
+
+ rc = g_vbgldata.status == VbglStatusReady? VINF_SUCCESS: VERR_VBGL_NOT_INITIALIZED;
+
+ // dprintf(("VbglEnter: rc = %d\n", rc));
+
+ return rc;
+}
+
+int vbglInitCommon (void)
+{
+ int rc = VINF_SUCCESS;
+
+ RT_ZERO(g_vbgldata);
+
+ g_vbgldata.status = VbglStatusInitializing;
+
+ rc = VbglPhysHeapInit ();
+
+ if (RT_SUCCESS(rc))
+ {
+ /* other subsystems, none yet */
+ ;
+ }
+ else
+ {
+ LogRel(("vbglInitCommon: VbglPhysHeapInit failed. rc=%Rrc\n", rc));
+ g_vbgldata.status = VbglStatusNotInitialized;
+ }
+
+ dprintf(("vbglInitCommon: rc = %d\n", rc));
+
+ return rc;
+}
+
+DECLVBGL(void) vbglTerminateCommon (void)
+{
+ VbglPhysHeapTerminate ();
+ g_vbgldata.status = VbglStatusNotInitialized;
+
+ return;
+}
+
+#ifdef VBGL_VBOXGUEST
+
+DECLVBGL(int) VbglInitPrimary(RTIOPORT portVMMDev, VMMDevMemory *pVMMDevMemory)
+{
+ int rc = VINF_SUCCESS;
+
+# ifdef RT_OS_WINDOWS /** @todo r=bird: this doesn't make sense. Is there something special going on on windows? */
+ dprintf(("vbglInit: starts g_vbgldata.status %d\n", g_vbgldata.status));
+
+ if ( g_vbgldata.status == VbglStatusInitializing
+ || g_vbgldata.status == VbglStatusReady)
+ {
+ /* Initialization is already in process. */
+ return rc;
+ }
+# else
+ dprintf(("vbglInit: starts\n"));
+# endif
+
+ rc = vbglInitCommon ();
+
+ if (RT_SUCCESS(rc))
+ {
+ g_vbgldata.portVMMDev = portVMMDev;
+ g_vbgldata.pVMMDevMemory = pVMMDevMemory;
+
+ g_vbgldata.status = VbglStatusReady;
+
+ vbglR0QueryHostVersion();
+ }
+ else
+ {
+ g_vbgldata.status = VbglStatusNotInitialized;
+ }
+
+ return rc;
+}
+
+DECLVBGL(void) VbglTerminate (void)
+{
+ vbglTerminateCommon ();
+
+ return;
+}
+
+
+#else /* !VBGL_VBOXGUEST */
+
+DECLVBGL(int) VbglInitClient(void)
+{
+ int rc = VINF_SUCCESS;
+
+ if ( g_vbgldata.status == VbglStatusInitializing
+ || g_vbgldata.status == VbglStatusReady)
+ {
+ /* Initialization is already in process. */
+ return rc;
+ }
+
+ rc = vbglInitCommon ();
+
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTSemMutexCreate(&g_vbgldata.mutexDriverInit);
+ if (RT_SUCCESS(rc))
+ {
+ /* Try to obtain VMMDev port via IOCTL to VBoxGuest main driver. */
+ vbglQueryDriverInfo ();
+
+# ifdef VBOX_WITH_HGCM
+ rc = vbglR0HGCMInit ();
+# endif /* VBOX_WITH_HGCM */
+
+ if (RT_FAILURE(rc))
+ {
+ RTSemMutexDestroy(g_vbgldata.mutexDriverInit);
+ g_vbgldata.mutexDriverInit = NIL_RTSEMMUTEX;
+ }
+ }
+
+ if (RT_FAILURE(rc))
+ {
+ vbglTerminateCommon ();
+ }
+
+ }
+
+ return rc;
+}
+
+DECLVBGL(void) VbglTerminate (void)
+{
+# ifdef VBOX_WITH_HGCM
+ vbglR0HGCMTerminate ();
+# endif
+
+ /* driver open could fail, which does not prevent VbglInit from succeeding,
+ * close the driver only if it is opened */
+ if (vbglDriverIsOpened(&g_vbgldata.driver))
+ vbglDriverClose(&g_vbgldata.driver);
+ RTSemMutexDestroy(g_vbgldata.mutexDriverInit);
+ g_vbgldata.mutexDriverInit = NIL_RTSEMMUTEX;
+
+ /* note: do vbglTerminateCommon as a last step since it zeroez up the g_vbgldata
+ * conceptually, doing vbglTerminateCommon last is correct
+ * since this is the reverse order to how init is done */
+ vbglTerminateCommon ();
+
+ return;
+}
+
+int vbglGetDriver(VBGLDRIVER **ppDriver)
+{
+ if (g_vbgldata.status != VbglStatusReady)
+ {
+ vbglQueryDriverInfo();
+ if (g_vbgldata.status != VbglStatusReady)
+ return VERR_TRY_AGAIN;
+ }
+ *ppDriver = &g_vbgldata.driver;
+ return VINF_SUCCESS;
+}
+
+#endif /* !VBGL_VBOXGUEST */
--- /dev/null
+KBUILD_EXTMOD=${srctree}/ubuntu/vbox
+# $Revision: 115996 $
+## @file
+# VirtualBox Guest Additions Module Makefile.
+#
+
+#
+# Copyright (C) 2006-2015 Oracle Corporation
+#
+# This file is part of VirtualBox Open Source Edition (OSE), as
+# available from http://www.virtualbox.org. This file is free software;
+# you can redistribute it and/or modify it under the terms of the GNU
+# General Public License (GPL) as published by the Free Software
+# Foundation, in version 2 as it comes in the "COPYING" file of the
+# VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+#
+
+# Linux kbuild sets this to our source directory if we are called from there
+obj ?= $(CURDIR)
+include $(obj)/Makefile.include.header
+
+MOD_NAME = vboxguest
+
+MOD_OBJS = \
+ VBoxGuest-linux.o \
+ VBoxGuest.o \
+ GenericRequest.o \
+ HGCMInternal.o \
+ Init.o \
+ PhysHeap.o \
+ SysHlp.o \
+ VMMDev.o \
+ r0drv/alloc-r0drv.o \
+ r0drv/initterm-r0drv.o \
+ r0drv/memobj-r0drv.o \
+ r0drv/mpnotification-r0drv.o \
+ r0drv/powernotification-r0drv.o \
+ r0drv/linux/alloc-r0drv-linux.o \
+ r0drv/linux/assert-r0drv-linux.o \
+ r0drv/linux/initterm-r0drv-linux.o \
+ r0drv/linux/memobj-r0drv-linux.o \
+ r0drv/linux/memuserkernel-r0drv-linux.o \
+ r0drv/linux/mp-r0drv-linux.o \
+ r0drv/linux/mpnotification-r0drv-linux.o \
+ r0drv/linux/process-r0drv-linux.o \
+ r0drv/linux/semevent-r0drv-linux.o \
+ r0drv/linux/semeventmulti-r0drv-linux.o \
+ r0drv/linux/semfastmutex-r0drv-linux.o \
+ r0drv/linux/semmutex-r0drv-linux.o \
+ r0drv/linux/spinlock-r0drv-linux.o \
+ r0drv/linux/thread-r0drv-linux.o \
+ r0drv/linux/thread2-r0drv-linux.o \
+ r0drv/linux/time-r0drv-linux.o \
+ r0drv/linux/timer-r0drv-linux.o \
+ r0drv/linux/RTLogWriteDebugger-r0drv-linux.o \
+ r0drv/generic/semspinmutex-r0drv-generic.o \
+ common/alloc/alloc.o \
+ common/err/RTErrConvertFromErrno.o \
+ common/err/RTErrConvertToErrno.o \
+ common/log/log.o \
+ common/log/logellipsis.o \
+ common/log/logrel.o \
+ common/log/logrelellipsis.o \
+ common/log/logcom.o \
+ common/log/logformat.o \
+ common/misc/RTAssertMsg1Weak.o \
+ common/misc/RTAssertMsg2.o \
+ common/misc/RTAssertMsg2Add.o \
+ common/misc/RTAssertMsg2AddWeak.o \
+ common/misc/RTAssertMsg2AddWeakV.o \
+ common/misc/RTAssertMsg2Weak.o \
+ common/misc/RTAssertMsg2WeakV.o \
+ common/misc/assert.o \
+ common/misc/thread.o \
+ common/string/RTStrCopy.o \
+ common/string/RTStrCopyEx.o \
+ common/string/RTStrCopyP.o \
+ common/string/strformat.o \
+ common/string/strformatrt.o \
+ common/string/strformattype.o \
+ common/string/strprintf.o \
+ common/string/strtonum.o \
+ common/table/avlpv.o \
+ common/time/time.o \
+ generic/RTAssertShouldPanic-generic.o \
+ generic/RTLogWriteStdErr-stub-generic.o \
+ generic/RTLogWriteStdOut-stub-generic.o \
+ generic/RTMpGetCoreCount-generic.o \
+ generic/RTSemEventWait-2-ex-generic.o \
+ generic/RTSemEventWaitNoResume-2-ex-generic.o \
+ generic/RTSemEventMultiWait-2-ex-generic.o \
+ generic/RTSemEventMultiWaitNoResume-2-ex-generic.o \
+ generic/rtStrFormatKernelAddress-generic.o \
+ generic/errvars-generic.o \
+ generic/mppresent-generic.o \
+ VBox/log-vbox.o \
+ VBox/logbackdoor.o
+ifeq ($(BUILD_TARGET_ARCH),x86)
+MOD_OBJS += \
+ common/math/gcc/divdi3.o \
+ common/math/gcc/moddi3.o \
+ common/math/gcc/udivdi3.o \
+ common/math/gcc/udivmoddi4.o \
+ common/math/gcc/umoddi3.o \
+ common/math/gcc/qdivrem.o
+endif
+ifeq ($(BUILD_TARGET_ARCH),amd64)
+MOD_OBJS += common/alloc/heapsimple.o
+endif
+
+MOD_DEFS = -DVBOX -DRT_OS_LINUX -DIN_RING0 -DIN_RT_R0 -DIN_GUEST \
+ -DIN_GUEST_R0 -DIN_MODULE -DRT_WITH_VBOX -DVBGL_VBOXGUEST \
+ -DVBOX_WITH_HGCM
+ifeq ($(BUILD_TARGET_ARCH),amd64)
+ MOD_DEFS += -DRT_ARCH_AMD64
+else
+ MOD_DEFS += -DRT_ARCH_X86
+endif
+ifeq ($(BUILD_TARGET_ARCH),amd64)
+ MOD_DEFS += -DVBOX_WITH_64_BITS_GUESTS
+endif
+MOD_INCL = $(addprefix -I$(KBUILD_EXTMOD),/ /include /r0drv/linux)
+MOD_INCL += $(addprefix -I$(KBUILD_EXTMOD)/vboxguest,/ /include /r0drv/linux)
+
+ifneq ($(wildcard $(KBUILD_EXTMOD)/vboxguest),)
+ MANGLING := $(KBUILD_EXTMOD)/vboxguest/include/VBox/VBoxGuestMangling.h
+else
+ MANGLING := $(KBUILD_EXTMOD)/include/VBox/VBoxGuestMangling.h
+endif
+ifeq ($(KERN_VERSION),24)
+ ## @todo move to MOD_DEFS when we have finished refactoring
+ MOD_CFLAGS = -DEXPORT_SYMTAB
+else
+ MOD_CFLAGS = -Wno-declaration-after-statement -include $(MANGLING) -fno-pie
+endif
+
+MOD_CLEAN = . linux r0drv generic r0drv/linux r0drv/generic VBox \
+ common/alloc common/err common/log common/math/gcc common/misc \
+ common/string common/table common/time
+
+include $(obj)/Makefile.include.footer
+
+check: $(MOD_NAME)
+ @if ! readelf -p __ksymtab_strings vboxguest.ko | grep -E "\[.*\] *(RT|g_..*RT.*)"; then \
+ echo "All exported IPRT symbols are properly renamed!"; \
+ else \
+ echo "error: Some exported IPRT symbols was not properly renamed! See above." >&2; \
+ false; \
+ fi
--- /dev/null
+#
+# VirtualBox Guest Additions kernel module Makefile, common parts.
+#
+# See Makefile.include.header for details of how to use this.
+#
+# Copyright (C) 2006-2015 Oracle Corporation
+#
+# This file is part of VirtualBox Open Source Edition (OSE), as
+# available from http://www.virtualbox.org. This file is free software;
+# you can redistribute it and/or modify it under the terms of the GNU
+# General Public License (GPL) as published by the Free Software
+# Foundation, in version 2 as it comes in the "COPYING" file of the
+# VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+#
+
+# override is required by the Debian guys
+override MODULE = $(MOD_NAME)
+OBJS = $(MOD_OBJS)
+
+ifneq ($(MAKECMDGOALS),clean)
+
+KBUILD_VERBOSE ?= 1
+
+#
+# Compiler options
+#
+ifndef INCL
+ INCL := $(addprefix -I,$(KERN_INCL) $(EXTRA_INCL))
+ ifndef KBUILD_EXTMOD
+ KBUILD_EXTMOD := $(shell pwd)
+ endif
+ INCL += $(MOD_INCL)
+ export INCL
+endif
+KFLAGS := -D__KERNEL__ -DMODULE $(MOD_DEFS)
+ifeq ($(BUILD_TYPE),debug)
+ KFLAGS += -DDEBUG -DDEBUG_$(subst $(subst _, ,_),_,$(USERNAME)) -DDEBUG_USERNAME=$(subst $(subst _, ,_),_,$(USERNAME))
+endif
+
+ifeq ($(KERN_VERSION), 24)
+#
+# 2.4
+#
+
+ifeq ($(BUILD_TARGET_ARCH),amd64)
+ KFLAGS += -mcmodel=kernel
+endif
+
+CFLAGS := -O2 -DVBOX_LINUX_2_4 $(MOD_CFLAGS) $(INCL) $(KFLAGS) $(MOD_EXTRA) $(KDEBUG)
+MODULE_EXT := o
+
+# 2.4 Module linking
+$(MODULE).o: $(OBJS)
+ $(LD) -o $@ -r $(OBJS)
+
+.PHONY: $(MODULE)
+all: $(MODULE)
+$(MODULE): $(MODULE).o
+
+else
+#
+# 2.6 and later
+#
+
+MODULE_EXT := ko
+
+$(MODULE)-y := $(OBJS)
+
+# build defs
+EXTRA_CFLAGS += $(MOD_CFLAGS) $(INCL) $(KFLAGS) $(MOD_EXTRA) $(KDEBUG)
+
+.PHONY: $(MODULE)
+all: $(MODULE)
+
+obj-m += $(MODULE).o
+
+JOBS := $(shell (getconf _NPROCESSORS_ONLN || grep -Ec '^processor|^CPU[0-9]' /proc/cpuinfo) 2>/dev/null)
+ifeq ($(JOBS),0)
+ JOBS := 1
+endif
+
+# OL/UEK: disable module signing for external modules -- we don't have any private key
+$(MODULE):
+ $(MAKE) KBUILD_VERBOSE=$(KBUILD_VERBOSE) CONFIG_MODULE_SIG= -C $(KERN_DIR) SUBDIRS=$(CURDIR) SRCROOT=$(CURDIR) -j$(JOBS) modules
+
+modules_install:
+ $(MAKE) KBUILD_VERBOSE=$(KBUILD_VERBOSE) CONFIG_MODULE_SIG= -C $(KERN_DIR) SUBDIRS=$(CURDIR) SRCROOT=$(CURDIR) modules_install
+
+endif
+
+install: $(MODULE)
+ @mkdir -p $(MODULE_DIR); \
+ install -m 0644 -o root -g root $(MODULE).$(MODULE_EXT) $(MODULE_DIR); \
+ PATH="$(PATH):/bin:/sbin" depmod -a;
+
+endif # eq($(MAKECMDGOALS),clean)
+
+clean:
+ for f in $(MOD_CLEAN); do rm -f $$f/*.o $$f/.*.cmd $$f/.*.flags; done
+ rm -rf .$(MOD_NAME)* .tmp_ver* $(MOD_NAME).* Modules.symvers modules.order
--- /dev/null
+#
+# VirtualBox Guest Additions kernel module Makefile, common parts.
+#
+# (For 2.6.x, the main file must be called 'Makefile'!)
+#
+# Copyright (C) 2006-2015 Oracle Corporation
+#
+# This file is part of VirtualBox Open Source Edition (OSE), as
+# available from http://www.virtualbox.org. This file is free software;
+# you can redistribute it and/or modify it under the terms of the GNU
+# General Public License (GPL) as published by the Free Software
+# Foundation, in version 2 as it comes in the "COPYING" file of the
+# VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+#
+
+# Testing:
+# * Building with KERN_VER set to an installed but non-current kernel works and
+# installs to the right location.
+# * Building with KERN_DIR and/or MODULE_DIR set uses the value specified and
+# the default value for the unspecified one if any.
+
+#
+# These file should be included by the Makefiles for any kernel modules we
+# build as part of the Guest Additions. The intended way of doing this is as
+# follows:
+#
+# # Linux kbuild sets this to our source directory if we are called from
+# # there
+# obj ?= $(CURDIR)
+# include $(obj)/Makefile.include.header
+# MOD_NAME = <name of the module to be built, without extension>
+# MOD_OBJS = <list of object files which should be included>
+# MOD_DEFS = <any additional defines which this module needs>
+# MOD_INCL = <any additional include paths which this module needs>
+# MOD_CFLAGS = <any additional CFLAGS which this module needs>
+# MOD_CLEAN = <list of directories that the clean target should look at>
+# include $(obj)/Makefile.include.footer
+#
+# The kmk kBuild define KBUILD_TARGET_ARCH is available.
+#
+
+
+#
+# First, figure out which architecture we're targeting and the build type.
+# (We have to support basic cross building (ARCH=i386|x86_64).)
+# While at it, warn about BUILD_* vars found to help with user problems.
+#
+ifeq ($(filter-out x86_64 amd64 AMD64,$(shell uname -m)),)
+ BUILD_TARGET_ARCH_DEF := amd64
+else
+ BUILD_TARGET_ARCH_DEF := x86
+endif
+ifneq ($(filter-out amd64 x86,$(BUILD_TARGET_ARCH)),)
+ $(warning Ignoring unknown BUILD_TARGET_ARCH value '$(BUILD_TARGET_ARCH)'.)
+ BUILD_TARGET_ARCH :=
+endif
+ifeq ($(BUILD_TARGET_ARCH),)
+ ifeq ($(ARCH),x86_64)
+ BUILD_TARGET_ARCH := amd64
+ else
+ ifeq ($(ARCH),i386)
+ ifeq ($(CONFIG_X86_32),y)
+ BUILD_TARGET_ARCH := x86
+ else
+ BUILD_TARGET_ARCH := amd64
+ endif
+ else
+ ifeq ($(ARCH),x86)
+ ifeq ($(CONFIG_X86_32),y)
+ BUILD_TARGET_ARCH := x86
+ else
+ BUILD_TARGET_ARCH := amd64
+ endif
+ else
+ BUILD_TARGET_ARCH := $(BUILD_TARGET_ARCH_DEF)
+ endif
+ endif
+ endif
+else
+ ifneq ($(BUILD_TARGET_ARCH),$(BUILD_TARGET_ARCH_DEF))
+ $(warning Using BUILD_TARGET_ARCH='$(BUILD_TARGET_ARCH)' from the $(origin BUILD_TARGET_ARCH).)
+ endif
+endif
+
+ifneq ($(filter-out release profile debug strict,$(BUILD_TYPE)),)
+ $(warning Ignoring unknown BUILD_TYPE value '$(BUILD_TYPE)'.)
+ BUILD_TYPE :=
+endif
+ifeq ($(BUILD_TYPE),)
+ BUILD_TYPE := release
+else
+ ifneq ($(BUILD_TYPE),release)
+ $(warning Using BUILD_TYPE='$(BUILD_TYPE)' from the $(origin BUILD_TYPE).)
+ endif
+endif
+ifeq ($(USERNAME),)
+ USERNAME := noname
+endif
+
+ifneq ($(MAKECMDGOALS),clean)
+
+ifeq ($(KERNELRELEASE),)
+
+ #
+ # building from this directory
+ #
+
+ # target kernel version
+ ifndef KERN_VER
+ KERN_VER := $(shell uname -r)
+ else
+ ifneq ($(shell if test -d /lib/modules/$(KERN_VER)/build; then echo yes; fi),yes)
+ KERN_VER := $(shell uname -r)
+ endif
+ endif
+
+ # kernel base directory
+ ifndef KERN_DIR
+ KERN_DIR := /lib/modules/$(KERN_VER)/build
+ ifneq ($(shell if test -d $(KERN_DIR); then echo yes; fi),yes)
+ KERN_DIR := /usr/src/linux
+ ifneq ($(shell if test -d $(KERN_DIR); then echo yes; fi),yes)
+ $(error Error: unable to find the sources of your current Linux kernel. \
+ Specify KERN_DIR=<directory> and run Make again)
+ endif
+ $(warning Warning: using /usr/src/linux as the source directory of your \
+ Linux kernel. If this is not correct, specify \
+ KERN_DIR=<directory> and run Make again.)
+ endif
+ else
+ ifneq ($(shell if test -d $(KERN_DIR); then echo yes; fi),yes)
+ $(error Error: KERN_DIR does not point to a directory)
+ endif
+ endif
+
+ # includes
+ ifndef KERN_INCL
+ KERN_INCL = $(KERN_DIR)/include
+ endif
+ ifneq ($(shell if test -d $(KERN_INCL); then echo yes; fi),yes)
+ $(error Error: unable to find the include directory for your current Linux \
+ kernel. Specify KERN_INCL=<directory> and run Make again)
+ endif
+
+ # module install dir, only for current kernel
+ ifneq ($(filter install install_rpm,$(MAKECMDGOALS)),)
+ ifndef MODULE_DIR
+ MODULE_DIR_TST := /lib/modules/$(KERN_VER)
+ ifeq ($(shell if test -d $(MODULE_DIR_TST); then echo yes; fi),yes)
+ MODULE_DIR := $(MODULE_DIR_TST)/misc
+ else
+ $(error Unable to find the folder to install the module to)
+ endif
+ endif # MODULE_DIR unspecified
+ endif
+
+ # guess kernel version (24 or 26)
+ ifeq ($(shell if grep '"2\.4\.' $(KERN_INCL)/linux/version.h > /dev/null; then echo yes; fi),yes)
+ KERN_VERSION := 24
+ else
+ KERN_VERSION := 26
+ endif
+
+else # neq($(KERNELRELEASE),)
+
+ #
+ # building from kbuild (make -C <kernel_directory> M=`pwd`)
+ #
+
+ # guess kernel version (24 or 26)
+ ifeq ($(shell if echo "$(VERSION).$(PATCHLEVEL)." | grep '2\.4\.' > /dev/null; then echo yes; fi),yes)
+ KERN_VERSION := 24
+ else
+ KERN_VERSION := 26
+ endif
+
+endif # neq($(KERNELRELEASE),)
+
+# debug - show guesses.
+ifdef DEBUG
+$(warning dbg: KERN_DIR = $(KERN_DIR))
+$(warning dbg: KERN_INCL = $(KERN_INCL))
+$(warning dbg: MODULE_DIR = $(MODULE_DIR))
+$(warning dbg: KERN_VERSION = $(KERN_VERSION))
+endif
+
+endif # eq($(MAKECMDGOALS),clean)
--- /dev/null
+/* $Id: PhysHeap.cpp $ */
+/** @file
+ * VBoxGuestLibR0 - Physical memory heap.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#include "VBGLInternal.h"
+
+#include <iprt/assert.h>
+#include <iprt/semaphore.h>
+#include <iprt/alloc.h>
+
+/* Physical memory heap consists of double linked list
+ * of chunks. Memory blocks are allocated inside these chunks
+ * and are members of Allocated and Free double linked lists.
+ *
+ * When allocating a block, we search in Free linked
+ * list for a suitable free block. If there is no such block,
+ * a new chunk is allocated and the new block is taken from
+ * the new chunk as the only chunk-sized free block.
+ * Allocated block is excluded from the Free list and goes to
+ * Alloc list.
+ *
+ * When freeing block, we check the pointer and then
+ * exclude block from Alloc list and move it to free list.
+ *
+ * For each chunk we maintain the allocated blocks counter.
+ * if 2 (or more) entire chunks are free they are immediately
+ * deallocated, so we always have at most 1 free chunk.
+ *
+ * When freeing blocks, two subsequent free blocks are always
+ * merged together. Current implementation merges blocks only
+ * when there is a block after the just freed one.
+ *
+ */
+
+#define VBGL_PH_ASSERT Assert
+#define VBGL_PH_ASSERTMsg AssertMsg
+
+// #define DUMPHEAP
+
+#ifdef DUMPHEAP
+# define VBGL_PH_dprintf(a) RTAssertMsg2Weak a
+#else
+# define VBGL_PH_dprintf(a)
+#endif
+
+/* Heap block signature */
+#define VBGL_PH_BLOCKSIGNATURE (0xADDBBBBB)
+
+
+/* Heap chunk signature */
+#define VBGL_PH_CHUNKSIGNATURE (0xADDCCCCC)
+/* Heap chunk allocation unit */
+#define VBGL_PH_CHUNKSIZE (0x10000)
+
+/* Heap block bit flags */
+#define VBGL_PH_BF_ALLOCATED (0x1)
+
+struct _VBGLPHYSHEAPBLOCK
+{
+ uint32_t u32Signature;
+
+ /* Size of user data in the block. Does not include the block header. */
+ uint32_t cbDataSize;
+
+ uint32_t fu32Flags;
+
+ struct _VBGLPHYSHEAPBLOCK *pNext;
+ struct _VBGLPHYSHEAPBLOCK *pPrev;
+
+ struct _VBGLPHYSHEAPCHUNK *pChunk;
+};
+
+struct _VBGLPHYSHEAPCHUNK
+{
+ uint32_t u32Signature;
+
+ /* Size of the chunk. Includes the chunk header. */
+ uint32_t cbSize;
+
+ /* Physical address of the chunk */
+ uint32_t physAddr;
+
+ /* Number of allocated blocks in the chunk */
+ int32_t cAllocatedBlocks;
+
+ struct _VBGLPHYSHEAPCHUNK *pNext;
+ struct _VBGLPHYSHEAPCHUNK *pPrev;
+};
+
+
+#ifndef DUMPHEAP
+#define dumpheap(a)
+#else
+void dumpheap (char *point)
+{
+ VBGL_PH_dprintf(("VBGL_PH dump at '%s'\n", point));
+
+ VBGL_PH_dprintf(("Chunks:\n"));
+
+ VBGLPHYSHEAPCHUNK *pChunk = g_vbgldata.pChunkHead;
+
+ while (pChunk)
+ {
+ VBGL_PH_dprintf(("%p: pNext = %p, pPrev = %p, sign = %08X, size = %8d, allocated = %8d, phys = %08X\n",
+ pChunk, pChunk->pNext, pChunk->pPrev, pChunk->u32Signature, pChunk->cbSize, pChunk->cAllocatedBlocks, pChunk->physAddr));
+
+ pChunk = pChunk->pNext;
+ }
+
+ VBGL_PH_dprintf(("Allocated blocks:\n"));
+
+ VBGLPHYSHEAPBLOCK *pBlock = g_vbgldata.pAllocBlocksHead;
+
+ while (pBlock)
+ {
+ VBGL_PH_dprintf(("%p: pNext = %p, pPrev = %p, sign = %08X, size = %8d, flags = %08X, pChunk = %p\n",
+ pBlock, pBlock->pNext, pBlock->pPrev, pBlock->u32Signature, pBlock->cbDataSize, pBlock->fu32Flags, pBlock->pChunk));
+
+ pBlock = pBlock->pNext;
+ }
+
+ VBGL_PH_dprintf(("Free blocks:\n"));
+
+ pBlock = g_vbgldata.pFreeBlocksHead;
+
+ while (pBlock)
+ {
+ VBGL_PH_dprintf(("%p: pNext = %p, pPrev = %p, sign = %08X, size = %8d, flags = %08X, pChunk = %p\n",
+ pBlock, pBlock->pNext, pBlock->pPrev, pBlock->u32Signature, pBlock->cbDataSize, pBlock->fu32Flags, pBlock->pChunk));
+
+ pBlock = pBlock->pNext;
+ }
+
+ VBGL_PH_dprintf(("VBGL_PH dump at '%s' done\n", point));
+}
+#endif
+
+
+DECLINLINE(void *) vbglPhysHeapBlock2Data (VBGLPHYSHEAPBLOCK *pBlock)
+{
+ return (void *)(pBlock? (char *)pBlock + sizeof (VBGLPHYSHEAPBLOCK): NULL);
+}
+
+DECLINLINE(VBGLPHYSHEAPBLOCK *) vbglPhysHeapData2Block (void *p)
+{
+ VBGLPHYSHEAPBLOCK *pBlock = (VBGLPHYSHEAPBLOCK *)(p? (char *)p - sizeof (VBGLPHYSHEAPBLOCK): NULL);
+
+ VBGL_PH_ASSERTMsg(pBlock == NULL || pBlock->u32Signature == VBGL_PH_BLOCKSIGNATURE,
+ ("pBlock->u32Signature = %08X\n", pBlock->u32Signature));
+
+ return pBlock;
+}
+
+DECLINLINE(int) vbglPhysHeapEnter (void)
+{
+ int rc = RTSemFastMutexRequest(g_vbgldata.mutexHeap);
+
+ VBGL_PH_ASSERTMsg(RT_SUCCESS(rc),
+ ("Failed to request heap mutex, rc = %Rrc\n", rc));
+
+ return rc;
+}
+
+DECLINLINE(void) vbglPhysHeapLeave (void)
+{
+ RTSemFastMutexRelease(g_vbgldata.mutexHeap);
+}
+
+
+static void vbglPhysHeapInitBlock (VBGLPHYSHEAPBLOCK *pBlock, VBGLPHYSHEAPCHUNK *pChunk, uint32_t cbDataSize)
+{
+ VBGL_PH_ASSERT(pBlock != NULL);
+ VBGL_PH_ASSERT(pChunk != NULL);
+
+ pBlock->u32Signature = VBGL_PH_BLOCKSIGNATURE;
+ pBlock->cbDataSize = cbDataSize;
+ pBlock->fu32Flags = 0;
+ pBlock->pNext = NULL;
+ pBlock->pPrev = NULL;
+ pBlock->pChunk = pChunk;
+}
+
+
+static void vbglPhysHeapInsertBlock (VBGLPHYSHEAPBLOCK *pInsertAfter, VBGLPHYSHEAPBLOCK *pBlock)
+{
+ VBGL_PH_ASSERTMsg(pBlock->pNext == NULL,
+ ("pBlock->pNext = %p\n", pBlock->pNext));
+ VBGL_PH_ASSERTMsg(pBlock->pPrev == NULL,
+ ("pBlock->pPrev = %p\n", pBlock->pPrev));
+
+ if (pInsertAfter)
+ {
+ pBlock->pNext = pInsertAfter->pNext;
+ pBlock->pPrev = pInsertAfter;
+
+ if (pInsertAfter->pNext)
+ {
+ pInsertAfter->pNext->pPrev = pBlock;
+ }
+
+ pInsertAfter->pNext = pBlock;
+ }
+ else
+ {
+ /* inserting to head of list */
+ pBlock->pPrev = NULL;
+
+ if (pBlock->fu32Flags & VBGL_PH_BF_ALLOCATED)
+ {
+ pBlock->pNext = g_vbgldata.pAllocBlocksHead;
+
+ if (g_vbgldata.pAllocBlocksHead)
+ {
+ g_vbgldata.pAllocBlocksHead->pPrev = pBlock;
+ }
+
+ g_vbgldata.pAllocBlocksHead = pBlock;
+ }
+ else
+ {
+ pBlock->pNext = g_vbgldata.pFreeBlocksHead;
+
+ if (g_vbgldata.pFreeBlocksHead)
+ {
+ g_vbgldata.pFreeBlocksHead->pPrev = pBlock;
+ }
+
+ g_vbgldata.pFreeBlocksHead = pBlock;
+ }
+ }
+}
+
+static void vbglPhysHeapExcludeBlock (VBGLPHYSHEAPBLOCK *pBlock)
+{
+ if (pBlock->pNext)
+ {
+ pBlock->pNext->pPrev = pBlock->pPrev;
+ }
+ else
+ {
+ /* this is tail of list but we do not maintain tails of block lists.
+ * so do nothing.
+ */
+ ;
+ }
+
+ if (pBlock->pPrev)
+ {
+ pBlock->pPrev->pNext = pBlock->pNext;
+ }
+ else
+ {
+ /* this is head of list but we do not maintain tails of block lists. */
+ if (pBlock->fu32Flags & VBGL_PH_BF_ALLOCATED)
+ {
+ g_vbgldata.pAllocBlocksHead = pBlock->pNext;
+ }
+ else
+ {
+ g_vbgldata.pFreeBlocksHead = pBlock->pNext;
+ }
+ }
+
+ pBlock->pNext = NULL;
+ pBlock->pPrev = NULL;
+}
+
+static VBGLPHYSHEAPBLOCK *vbglPhysHeapChunkAlloc (uint32_t cbSize)
+{
+ RTCCPHYS physAddr;
+ VBGLPHYSHEAPCHUNK *pChunk;
+ VBGLPHYSHEAPBLOCK *pBlock;
+ VBGL_PH_dprintf(("Allocating new chunk of size %d\n", cbSize));
+
+ /* Compute chunk size to allocate */
+ if (cbSize < VBGL_PH_CHUNKSIZE)
+ {
+ /* Includes case of block size 0 during initialization */
+ cbSize = VBGL_PH_CHUNKSIZE;
+ }
+ else
+ {
+ /* Round up to next chunk size, which must be power of 2 */
+ cbSize = (cbSize + (VBGL_PH_CHUNKSIZE - 1)) & ~(VBGL_PH_CHUNKSIZE - 1);
+ }
+
+ physAddr = 0;
+ /* This function allocates physical contiguous memory (below 4GB) according to the IPRT docs.
+ * Address < 4G is required for the port IO.
+ */
+ pChunk = (VBGLPHYSHEAPCHUNK *)RTMemContAlloc (&physAddr, cbSize);
+
+ if (!pChunk)
+ {
+ LogRel(("vbglPhysHeapChunkAlloc: failed to alloc %u contiguous bytes.\n", cbSize));
+ return NULL;
+ }
+
+ AssertRelease(physAddr < _4G && physAddr + cbSize <= _4G);
+
+ pChunk->u32Signature = VBGL_PH_CHUNKSIGNATURE;
+ pChunk->cbSize = cbSize;
+ pChunk->physAddr = (uint32_t)physAddr;
+ pChunk->cAllocatedBlocks = 0;
+ pChunk->pNext = g_vbgldata.pChunkHead;
+ pChunk->pPrev = NULL;
+
+ /* Initialize the free block, which now occupies entire chunk. */
+ pBlock = (VBGLPHYSHEAPBLOCK *)((char *)pChunk + sizeof (VBGLPHYSHEAPCHUNK));
+
+ vbglPhysHeapInitBlock (pBlock, pChunk, cbSize - sizeof (VBGLPHYSHEAPCHUNK) - sizeof (VBGLPHYSHEAPBLOCK));
+
+ vbglPhysHeapInsertBlock (NULL, pBlock);
+
+ g_vbgldata.pChunkHead = pChunk;
+
+ VBGL_PH_dprintf(("Allocated chunk %p, block = %p size=%x\n", pChunk, pBlock, cbSize));
+
+ return pBlock;
+}
+
+
+void vbglPhysHeapChunkDelete (VBGLPHYSHEAPCHUNK *pChunk)
+{
+ char *p;
+ VBGL_PH_ASSERT(pChunk != NULL);
+ VBGL_PH_ASSERTMsg(pChunk->u32Signature == VBGL_PH_CHUNKSIGNATURE,
+ ("pChunk->u32Signature = %08X\n", pChunk->u32Signature));
+
+ VBGL_PH_dprintf(("Deleting chunk %p size %x\n", pChunk, pChunk->cbSize));
+
+ /* first scan the chunk and exclude all blocks from lists */
+
+ p = (char *)pChunk + sizeof (VBGLPHYSHEAPCHUNK);
+
+ while (p < (char *)pChunk + pChunk->cbSize)
+ {
+ VBGLPHYSHEAPBLOCK *pBlock = (VBGLPHYSHEAPBLOCK *)p;
+
+ p += pBlock->cbDataSize + sizeof (VBGLPHYSHEAPBLOCK);
+
+ vbglPhysHeapExcludeBlock (pBlock);
+ }
+
+ VBGL_PH_ASSERTMsg(p == (char *)pChunk + pChunk->cbSize,
+ ("p = %p, (char *)pChunk + pChunk->cbSize = %p, pChunk->cbSize = %08X\n",
+ p, (char *)pChunk + pChunk->cbSize, pChunk->cbSize));
+
+ /* Exclude chunk from the chunk list */
+ if (pChunk->pNext)
+ {
+ pChunk->pNext->pPrev = pChunk->pPrev;
+ }
+ else
+ {
+ /* we do not maintain tail */
+ ;
+ }
+
+ if (pChunk->pPrev)
+ {
+ pChunk->pPrev->pNext = pChunk->pNext;
+ }
+ else
+ {
+ /* the chunk was head */
+ g_vbgldata.pChunkHead = pChunk->pNext;
+ }
+
+ RTMemContFree (pChunk, pChunk->cbSize);
+}
+
+
+DECLVBGL(void *) VbglPhysHeapAlloc (uint32_t cbSize)
+{
+ VBGLPHYSHEAPBLOCK *pBlock, *iter;
+ int rc = vbglPhysHeapEnter ();
+
+ if (RT_FAILURE(rc))
+ return NULL;
+
+ dumpheap ("pre alloc");
+
+ pBlock = NULL;
+
+ /* If there are free blocks in the heap, look at them. */
+ iter = g_vbgldata.pFreeBlocksHead;
+
+ /* There will be not many blocks in the heap, so
+ * linear search would be fast enough.
+ */
+
+ while (iter)
+ {
+ if (iter->cbDataSize == cbSize)
+ {
+ /* exact match */
+ pBlock = iter;
+ break;
+ }
+
+ /* Looking for a free block with nearest size */
+ if (iter->cbDataSize > cbSize)
+ {
+ if (pBlock)
+ {
+ if (iter->cbDataSize < pBlock->cbDataSize)
+ {
+ pBlock = iter;
+ }
+ }
+ else
+ {
+ pBlock = iter;
+ }
+ }
+
+ iter = iter->pNext;
+ }
+
+ if (!pBlock)
+ {
+ /* No free blocks, allocate a new chunk,
+ * the only free block of the chunk will
+ * be returned.
+ */
+ pBlock = vbglPhysHeapChunkAlloc (cbSize);
+ }
+
+ if (pBlock)
+ {
+ VBGL_PH_ASSERTMsg(pBlock->u32Signature == VBGL_PH_BLOCKSIGNATURE,
+ ("pBlock = %p, pBlock->u32Signature = %08X\n", pBlock, pBlock->u32Signature));
+ VBGL_PH_ASSERTMsg((pBlock->fu32Flags & VBGL_PH_BF_ALLOCATED) == 0,
+ ("pBlock = %p, pBlock->fu32Flags = %08X\n", pBlock, pBlock->fu32Flags));
+
+ /* We have a free block, either found or allocated. */
+
+ if (pBlock->cbDataSize > 2*(cbSize + sizeof (VBGLPHYSHEAPBLOCK)))
+ {
+ /* Data will occupy less than a half of the block,
+ * the block should be split.
+ */
+ iter = (VBGLPHYSHEAPBLOCK *)((char *)pBlock + sizeof (VBGLPHYSHEAPBLOCK) + cbSize);
+
+ /* Init the new 'iter' block, initialized blocks are always marked as free. */
+ vbglPhysHeapInitBlock (iter, pBlock->pChunk, pBlock->cbDataSize - cbSize - sizeof (VBGLPHYSHEAPBLOCK));
+
+ pBlock->cbDataSize = cbSize;
+
+ /* Insert the new 'iter' block after the 'pBlock' in the free list */
+ vbglPhysHeapInsertBlock (pBlock, iter);
+ }
+
+ /* Exclude pBlock from free list */
+ vbglPhysHeapExcludeBlock (pBlock);
+
+ /* Mark as allocated */
+ pBlock->fu32Flags |= VBGL_PH_BF_ALLOCATED;
+
+ /* Insert to allocated list */
+ vbglPhysHeapInsertBlock (NULL, pBlock);
+
+ /* Adjust the chunk allocated blocks counter */
+ pBlock->pChunk->cAllocatedBlocks++;
+ }
+
+ dumpheap ("post alloc");
+
+ vbglPhysHeapLeave ();
+ VBGL_PH_dprintf(("VbglPhysHeapAlloc %x size %x\n", vbglPhysHeapBlock2Data (pBlock), pBlock->cbDataSize));
+
+ return vbglPhysHeapBlock2Data (pBlock);
+}
+
+DECLVBGL(uint32_t) VbglPhysHeapGetPhysAddr (void *p)
+{
+ uint32_t physAddr = 0;
+ VBGLPHYSHEAPBLOCK *pBlock = vbglPhysHeapData2Block (p);
+
+ if (pBlock)
+ {
+ VBGL_PH_ASSERTMsg((pBlock->fu32Flags & VBGL_PH_BF_ALLOCATED) != 0,
+ ("pBlock = %p, pBlock->fu32Flags = %08X\n", pBlock, pBlock->fu32Flags));
+
+ if (pBlock->fu32Flags & VBGL_PH_BF_ALLOCATED)
+ physAddr = pBlock->pChunk->physAddr + (uint32_t)((uintptr_t)p - (uintptr_t)pBlock->pChunk);
+ }
+
+ return physAddr;
+}
+
+DECLVBGL(void) VbglPhysHeapFree(void *p)
+{
+ VBGLPHYSHEAPBLOCK *pBlock;
+ VBGLPHYSHEAPBLOCK *pNeighbour;
+
+ int rc = vbglPhysHeapEnter ();
+ if (RT_FAILURE(rc))
+ return;
+
+ dumpheap ("pre free");
+
+ pBlock = vbglPhysHeapData2Block (p);
+
+ if (!pBlock)
+ {
+ vbglPhysHeapLeave ();
+ return;
+ }
+
+ VBGL_PH_ASSERTMsg((pBlock->fu32Flags & VBGL_PH_BF_ALLOCATED) != 0,
+ ("pBlock = %p, pBlock->fu32Flags = %08X\n", pBlock, pBlock->fu32Flags));
+
+ /* Exclude from allocated list */
+ vbglPhysHeapExcludeBlock (pBlock);
+
+ dumpheap ("post exclude");
+
+ VBGL_PH_dprintf(("VbglPhysHeapFree %x size %x\n", p, pBlock->cbDataSize));
+
+ /* Mark as free */
+ pBlock->fu32Flags &= ~VBGL_PH_BF_ALLOCATED;
+
+ /* Insert to free list */
+ vbglPhysHeapInsertBlock (NULL, pBlock);
+
+ dumpheap ("post insert");
+
+ /* Adjust the chunk allocated blocks counter */
+ pBlock->pChunk->cAllocatedBlocks--;
+
+ VBGL_PH_ASSERT(pBlock->pChunk->cAllocatedBlocks >= 0);
+
+ /* Check if we can merge 2 free blocks. To simplify heap maintenance,
+ * we will look at block after the just freed one.
+ * This will not prevent us from detecting free memory chunks.
+ * Also in most cases blocks are deallocated in reverse allocation order
+ * and in that case the merging will work.
+ */
+
+ pNeighbour = (VBGLPHYSHEAPBLOCK *)((char *)p + pBlock->cbDataSize);
+
+ if ((char *)pNeighbour < (char *)pBlock->pChunk + pBlock->pChunk->cbSize
+ && (pNeighbour->fu32Flags & VBGL_PH_BF_ALLOCATED) == 0)
+ {
+ /* The next block is free as well. */
+
+ /* Adjust size of current memory block */
+ pBlock->cbDataSize += pNeighbour->cbDataSize + sizeof (VBGLPHYSHEAPBLOCK);
+
+ /* Exclude the next neighbour */
+ vbglPhysHeapExcludeBlock (pNeighbour);
+ }
+
+ dumpheap ("post merge");
+
+ /* now check if there are 2 or more free chunks */
+ if (pBlock->pChunk->cAllocatedBlocks == 0)
+ {
+ VBGLPHYSHEAPCHUNK *pChunk = g_vbgldata.pChunkHead;
+
+ uint32_t u32FreeChunks = 0;
+
+ while (pChunk)
+ {
+ if (pChunk->cAllocatedBlocks == 0)
+ {
+ u32FreeChunks++;
+ }
+
+ pChunk = pChunk->pNext;
+ }
+
+ if (u32FreeChunks > 1)
+ {
+ /* Delete current chunk, it will also exclude all free blocks
+ * remaining in the chunk from the free list, so the pBlock
+ * will also be invalid after this.
+ */
+ vbglPhysHeapChunkDelete (pBlock->pChunk);
+ }
+ }
+
+ dumpheap ("post free");
+
+ vbglPhysHeapLeave ();
+}
+
+DECLVBGL(int) VbglPhysHeapInit (void)
+{
+ int rc = VINF_SUCCESS;
+
+ /* Allocate the first chunk of the heap. */
+ VBGLPHYSHEAPBLOCK *pBlock = vbglPhysHeapChunkAlloc (0);
+
+ if (!pBlock)
+ rc = VERR_NO_MEMORY;
+
+ RTSemFastMutexCreate(&g_vbgldata.mutexHeap);
+
+ return rc;
+}
+
+DECLVBGL(void) VbglPhysHeapTerminate (void)
+{
+ while (g_vbgldata.pChunkHead)
+ {
+ vbglPhysHeapChunkDelete (g_vbgldata.pChunkHead);
+ }
+
+ RTSemFastMutexDestroy(g_vbgldata.mutexHeap);
+}
+
--- /dev/null
+/* $Id: SysHlp.cpp $ */
+/** @file
+ * VBoxGuestLibR0 - IDC with VBoxGuest and HGCM helpers.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#define LOG_GROUP LOG_GROUP_HGCM
+#include <VBox/log.h>
+
+#include <VBox/VBoxGuestLib.h>
+#include "SysHlp.h"
+
+#include <iprt/assert.h>
+
+#ifdef VBGL_VBOXGUEST
+
+#if !defined (RT_OS_WINDOWS)
+# include <iprt/memobj.h>
+# include <iprt/mem.h>
+#endif
+
+
+/**
+ * Internal worker for locking a range of linear addresses.
+ *
+ * @returns VBox status code.
+ * @param ppvCtx Where to store context data.
+ * @param pv The start of the range.
+ * @param u32Size The size of the range.
+ * @param fWriteAccess Lock for read-write (true) or readonly (false).
+ * @param fFlags HGCM call flags, VBGLR0_HGCM_F_XXX.
+ */
+int vbglLockLinear(void **ppvCtx, void *pv, uint32_t u32Size, bool fWriteAccess, uint32_t fFlags)
+{
+ int rc = VINF_SUCCESS;
+#ifndef RT_OS_WINDOWS
+ RTR0MEMOBJ MemObj = NIL_RTR0MEMOBJ;
+ uint32_t fAccess = RTMEM_PROT_READ | (fWriteAccess ? RTMEM_PROT_WRITE : 0);
+#endif
+
+ /* Zero size buffers shouldn't be locked. */
+ if (u32Size == 0)
+ {
+ Assert(pv == NULL);
+#ifdef RT_OS_WINDOWS
+ *ppvCtx = NULL;
+#else
+ *ppvCtx = NIL_RTR0MEMOBJ;
+#endif
+ return VINF_SUCCESS;
+ }
+
+ /** @todo just use IPRT here. the extra allocation shouldn't matter much...
+ * Then we can move all this up one level even. */
+#ifdef RT_OS_WINDOWS
+ PMDL pMdl = IoAllocateMdl(pv, u32Size, FALSE, FALSE, NULL);
+
+ if (pMdl == NULL)
+ {
+ rc = VERR_NOT_SUPPORTED;
+ AssertMsgFailed(("IoAllocateMdl %p %x failed!!\n", pv, u32Size));
+ }
+ else
+ {
+ __try {
+ /* Calls to MmProbeAndLockPages must be enclosed in a try/except block. */
+ RT_NOREF1(fFlags); /** @todo fFlags on windows */
+ MmProbeAndLockPages(pMdl,
+ /** @todo (fFlags & VBGLR0_HGCMCALL_F_MODE_MASK) == VBGLR0_HGCMCALL_F_USER? UserMode: KernelMode */
+ KernelMode,
+ (fWriteAccess) ? IoModifyAccess : IoReadAccess);
+
+ *ppvCtx = pMdl;
+
+ } __except(EXCEPTION_EXECUTE_HANDLER) {
+
+ IoFreeMdl(pMdl);
+ /** @todo */
+ rc = VERR_INVALID_PARAMETER;
+ AssertMsgFailed(("MmProbeAndLockPages %p %x failed!!\n", pv, u32Size));
+ }
+ }
+
+#else
+ /*
+ * Lock depending on context.
+ *
+ * Note: We will later use the memory object here to convert the HGCM
+ * linear buffer parameter into a physical page list. This is why
+ * we lock both kernel pages on all systems, even those where we
+ * know they aren't pageable.
+ */
+ if ((fFlags & VBGLR0_HGCMCALL_F_MODE_MASK) == VBGLR0_HGCMCALL_F_USER)
+ rc = RTR0MemObjLockUser(&MemObj, (RTR3PTR)pv, u32Size, fAccess, NIL_RTR0PROCESS);
+ else
+ rc = RTR0MemObjLockKernel(&MemObj, pv, u32Size, fAccess);
+ if (RT_SUCCESS(rc))
+ *ppvCtx = MemObj;
+ else
+ *ppvCtx = NIL_RTR0MEMOBJ;
+
+#endif
+
+ return rc;
+}
+
+void vbglUnlockLinear(void *pvCtx, void *pv, uint32_t u32Size)
+{
+#ifdef RT_OS_WINDOWS
+ PMDL pMdl = (PMDL)pvCtx;
+
+ Assert(pMdl);
+ if (pMdl != NULL)
+ {
+ MmUnlockPages(pMdl);
+ IoFreeMdl(pMdl);
+ }
+
+#else
+ RTR0MEMOBJ MemObj = (RTR0MEMOBJ)pvCtx;
+ int rc = RTR0MemObjFree(MemObj, false);
+ AssertRC(rc);
+
+#endif
+
+ NOREF(pv);
+ NOREF(u32Size);
+}
+
+#else /* !VBGL_VBOXGUEST */
+
+# ifdef RT_OS_OS2
+# include <VBox/VBoxGuest.h> /* for VBOXGUESTOS2IDCCONNECT */
+RT_C_DECLS_BEGIN
+/*
+ * On OS/2 we'll do the connecting in the assembly code of the
+ * client driver, exporting a g_VBoxGuestIDC symbol containing
+ * the connection information obtained from the 16-bit IDC.
+ */
+extern VBOXGUESTOS2IDCCONNECT g_VBoxGuestIDC;
+RT_C_DECLS_END
+# endif
+
+# if !defined(RT_OS_OS2) \
+ && !defined(RT_OS_WINDOWS)
+RT_C_DECLS_BEGIN
+extern DECLVBGL(void *) VBoxGuestIDCOpen(uint32_t *pu32Version);
+extern DECLVBGL(void) VBoxGuestIDCClose(void *pvOpaque);
+extern DECLVBGL(int) VBoxGuestIDCCall(void *pvOpaque, unsigned int iCmd, void *pvData, size_t cbSize, size_t *pcbReturn);
+RT_C_DECLS_END
+# endif
+
+bool vbglDriverIsOpened(VBGLDRIVER *pDriver)
+{
+# ifdef RT_OS_WINDOWS
+ return pDriver->pFileObject != NULL;
+# elif defined (RT_OS_OS2)
+ return pDriver->u32Session != UINT32_MAX && pDriver->u32Session != 0;
+# else
+ return pDriver->pvOpaque != NULL;
+# endif
+}
+
+int vbglDriverOpen(VBGLDRIVER *pDriver)
+{
+# ifdef RT_OS_WINDOWS
+ UNICODE_STRING uszDeviceName;
+ RtlInitUnicodeString(&uszDeviceName, L"\\Device\\VBoxGuest");
+
+ PDEVICE_OBJECT pDeviceObject = NULL;
+ PFILE_OBJECT pFileObject = NULL;
+
+ NTSTATUS rc = IoGetDeviceObjectPointer(&uszDeviceName, FILE_ALL_ACCESS, &pFileObject, &pDeviceObject);
+ if (NT_SUCCESS(rc))
+ {
+ Log(("vbglDriverOpen VBoxGuest successful pDeviceObject=%x\n", pDeviceObject));
+ pDriver->pDeviceObject = pDeviceObject;
+ pDriver->pFileObject = pFileObject;
+ return VINF_SUCCESS;
+ }
+ /** @todo return RTErrConvertFromNtStatus(rc)! */
+ Log(("vbglDriverOpen VBoxGuest failed with ntstatus=%x\n", rc));
+ return rc;
+
+# elif defined (RT_OS_OS2)
+ /*
+ * Just check whether the connection was made or not.
+ */
+ if ( g_VBoxGuestIDC.u32Version == VMMDEV_VERSION
+ && RT_VALID_PTR(g_VBoxGuestIDC.u32Session)
+ && RT_VALID_PTR(g_VBoxGuestIDC.pfnServiceEP))
+ {
+ pDriver->u32Session = g_VBoxGuestIDC.u32Session;
+ return VINF_SUCCESS;
+ }
+ pDriver->u32Session = UINT32_MAX;
+ Log(("vbglDriverOpen: failed\n"));
+ return VERR_FILE_NOT_FOUND;
+
+# else
+ uint32_t u32VMMDevVersion;
+ pDriver->pvOpaque = VBoxGuestIDCOpen(&u32VMMDevVersion);
+ if ( pDriver->pvOpaque
+ && u32VMMDevVersion == VMMDEV_VERSION)
+ return VINF_SUCCESS;
+
+ Log(("vbglDriverOpen: failed\n"));
+ return VERR_FILE_NOT_FOUND;
+# endif
+}
+
+# ifdef RT_OS_WINDOWS
+static NTSTATUS vbglDriverIOCtlCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
+{
+ RT_NOREF2(DeviceObject, Irp);
+ Log(("VBGL completion %x\n", Irp));
+
+ KEVENT *pEvent = (KEVENT *)Context;
+ KeSetEvent(pEvent, IO_NO_INCREMENT, FALSE);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+# endif
+
+int vbglDriverIOCtl(VBGLDRIVER *pDriver, uint32_t u32Function, void *pvData, uint32_t cbData)
+{
+ Log(("vbglDriverIOCtl: pDriver: %p, Func: %x, pvData: %p, cbData: %d\n", pDriver, u32Function, pvData, cbData));
+
+# ifdef RT_OS_WINDOWS
+ KEVENT Event;
+
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ /* Have to use the IoAllocateIRP method because this code is generic and
+ * must work in any thread context.
+ * The IoBuildDeviceIoControlRequest, which was used here, does not work
+ * when APCs are disabled, for example.
+ */
+ PIRP irp = IoAllocateIrp(pDriver->pDeviceObject->StackSize, FALSE);
+
+ Log(("vbglDriverIOCtl: irp %p, IRQL = %d\n", irp, KeGetCurrentIrql()));
+
+ if (irp == NULL)
+ {
+ Log(("vbglDriverIOCtl: IRP allocation failed!\n"));
+ return VERR_NO_MEMORY;
+ }
+
+ /*
+ * Setup the IRP_MJ_DEVICE_CONTROL IRP.
+ */
+
+ PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(irp);
+
+ nextStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
+ nextStack->MinorFunction = 0;
+ nextStack->DeviceObject = pDriver->pDeviceObject;
+ nextStack->Parameters.DeviceIoControl.OutputBufferLength = cbData;
+ nextStack->Parameters.DeviceIoControl.InputBufferLength = cbData;
+ nextStack->Parameters.DeviceIoControl.IoControlCode = u32Function;
+ nextStack->Parameters.DeviceIoControl.Type3InputBuffer = pvData;
+
+ irp->AssociatedIrp.SystemBuffer = pvData; /* Output buffer. */
+ irp->MdlAddress = NULL;
+
+ /* A completion routine is required to signal the Event. */
+ IoSetCompletionRoutine(irp, vbglDriverIOCtlCompletion, &Event, TRUE, TRUE, TRUE);
+
+ NTSTATUS rc = IoCallDriver(pDriver->pDeviceObject, irp);
+
+ if (NT_SUCCESS (rc))
+ {
+ /* Wait the event to be signalled by the completion routine. */
+ KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+
+ rc = irp->IoStatus.Status;
+
+ Log(("vbglDriverIOCtl: wait completed IRQL = %d\n", KeGetCurrentIrql()));
+ }
+
+ IoFreeIrp(irp);
+
+ if (rc != STATUS_SUCCESS)
+ Log(("vbglDriverIOCtl: ntstatus=%x\n", rc));
+
+ if (NT_SUCCESS(rc))
+ return VINF_SUCCESS;
+ if (rc == STATUS_INVALID_PARAMETER)
+ return VERR_INVALID_PARAMETER;
+ if (rc == STATUS_INVALID_BUFFER_SIZE)
+ return VERR_OUT_OF_RANGE;
+ return VERR_VBGL_IOCTL_FAILED;
+
+# elif defined (RT_OS_OS2)
+ if ( pDriver->u32Session
+ && pDriver->u32Session == g_VBoxGuestIDC.u32Session)
+ return g_VBoxGuestIDC.pfnServiceEP(pDriver->u32Session, u32Function, pvData, cbData, NULL);
+
+ Log(("vbglDriverIOCtl: No connection\n"));
+ return VERR_WRONG_ORDER;
+
+# else
+ return VBoxGuestIDCCall(pDriver->pvOpaque, u32Function, pvData, cbData, NULL);
+# endif
+}
+
+void vbglDriverClose(VBGLDRIVER *pDriver)
+{
+# ifdef RT_OS_WINDOWS
+ Log(("vbglDriverClose pDeviceObject=%x\n", pDriver->pDeviceObject));
+ ObDereferenceObject(pDriver->pFileObject);
+ pDriver->pFileObject = NULL;
+ pDriver->pDeviceObject = NULL;
+
+# elif defined (RT_OS_OS2)
+ pDriver->u32Session = 0;
+
+# else
+ VBoxGuestIDCClose(pDriver->pvOpaque);
+ pDriver->pvOpaque = NULL;
+# endif
+}
+
+#endif /* !VBGL_VBOXGUEST */
+
--- /dev/null
+/* $Id: SysHlp.h $ */
+/** @file
+ * VBoxGuestLibR0 - System dependent helpers internal header.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___VBoxGuestLib_SysHlp_h
+#define ___VBoxGuestLib_SysHlp_h
+
+#include <iprt/types.h>
+
+#ifdef RT_OS_WINDOWS
+# undef PAGE_SIZE
+# undef PAGE_SHIFT
+# include <iprt/nt/ntddk.h>
+/* XP DDK #defines ExFreePool to ExFreePoolWithTag. The latter does not exist on NT4, so...
+ * The same for ExAllocatePool.
+ */
+# undef ExAllocatePool
+# undef ExFreePool
+#endif
+
+typedef struct _VBGLDRIVER
+{
+#ifdef RT_OS_WINDOWS
+ PDEVICE_OBJECT pDeviceObject;
+ PFILE_OBJECT pFileObject;
+#elif defined (RT_OS_OS2)
+ uint32_t u32Session; /**< just for sanity checking. */
+#else /* PORTME */
+ void *pvOpaque;
+#endif
+} VBGLDRIVER;
+
+int vbglLockLinear(void **ppvCtx, void *pv, uint32_t cb, bool fWriteAccess, uint32_t fFlags);
+void vbglUnlockLinear(void *pvCtx, void *pv, uint32_t cb);
+
+
+#ifndef VBGL_VBOXGUEST
+
+/**
+ * Open VBoxGuest driver.
+ *
+ * @param pDriver Pointer to the driver structure.
+ *
+ * @return VBox status code
+ */
+int vbglDriverOpen(VBGLDRIVER *pDriver);
+
+/**
+ * Answers whether the VBoxGuest driver is opened
+ *
+ * @param pDriver Pointer to the driver structure.
+ *
+ * @return true - if opened, false - otherwise
+ */
+bool vbglDriverIsOpened(VBGLDRIVER *pDriver);
+
+/**
+ * Call VBoxGuest driver.
+ *
+ * @param pDriver Pointer to the driver structure.
+ * @param u32Function Function code.
+ * @param pvData Pointer to supplied in/out data buffer.
+ * @param cbData Size of data buffer.
+ *
+ * @returns VBox status code
+ */
+int vbglDriverIOCtl(VBGLDRIVER *pDriver, uint32_t u32Function, void *pvData, uint32_t cbData);
+
+/**
+ * Close VBoxGuest driver.
+ *
+ * @param pDriver Pointer to the driver structure.
+ *
+ * @returns VBox status code
+ */
+void vbglDriverClose(VBGLDRIVER *pDriver);
+
+#endif
+
+#endif
+
--- /dev/null
+/* $Id: VBGLInternal.h $ */
+/** @file
+ * VBoxGuestLibR0 - Internal header.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___VBoxGuestLib_VBGLInternal_h
+#define ___VBoxGuestLib_VBGLInternal_h
+
+#include <VBox/VMMDev.h>
+#include <VBox/VBoxGuest.h>
+#include <VBox/VBoxGuestLib.h>
+
+#include <VBox/log.h>
+
+
+#ifdef RT_OS_WINDOWS /** @todo dprintf() -> Log() */
+# if (defined(DEBUG) && !defined(NO_LOGGING)) || defined(LOG_ENABLED)
+# define dprintf(a) RTLogBackdoorPrintf a
+# else
+# define dprintf(a) do {} while (0)
+# endif
+#else
+# define dprintf(a) Log(a)
+#endif
+
+#include "SysHlp.h"
+
+struct _VBGLPHYSHEAPBLOCK;
+typedef struct _VBGLPHYSHEAPBLOCK VBGLPHYSHEAPBLOCK;
+struct _VBGLPHYSHEAPCHUNK;
+typedef struct _VBGLPHYSHEAPCHUNK VBGLPHYSHEAPCHUNK;
+
+#ifndef VBGL_VBOXGUEST
+struct VBGLHGCMHANDLEDATA
+{
+ uint32_t fAllocated;
+ VBGLDRIVER driver;
+};
+#endif
+
+enum VbglLibStatus
+{
+ VbglStatusNotInitialized = 0,
+ VbglStatusInitializing,
+ VbglStatusReady
+};
+
+/**
+ * Global VBGL ring-0 data.
+ * Lives in VbglR0Init.cpp.
+ */
+typedef struct VBGLDATA
+{
+ enum VbglLibStatus status;
+
+ RTIOPORT portVMMDev;
+
+ VMMDevMemory *pVMMDevMemory;
+
+ /**
+ * Physical memory heap data.
+ * @{
+ */
+
+ VBGLPHYSHEAPBLOCK *pFreeBlocksHead;
+ VBGLPHYSHEAPBLOCK *pAllocBlocksHead;
+ VBGLPHYSHEAPCHUNK *pChunkHead;
+
+ RTSEMFASTMUTEX mutexHeap;
+ /** @} */
+
+ /**
+ * The host version data.
+ */
+ VMMDevReqHostVersion hostVersion;
+
+
+#ifndef VBGL_VBOXGUEST
+ /**
+ * Handle for the main driver instance.
+ * @{
+ */
+
+ RTSEMMUTEX mutexDriverInit;
+
+ VBGLDRIVER driver;
+
+ /** @} */
+
+ /**
+ * Fast heap for HGCM handles data.
+ * @{
+ */
+
+ RTSEMFASTMUTEX mutexHGCMHandle;
+
+ struct VBGLHGCMHANDLEDATA aHGCMHandleData[64];
+
+ /** @} */
+#endif
+} VBGLDATA;
+
+
+#ifndef VBGL_DECL_DATA
+extern VBGLDATA g_vbgldata;
+#endif
+
+/**
+ * Internal macro for checking whether we can pass physical page lists to the
+ * host.
+ *
+ * ASSUMES that vbglR0Enter has been called already.
+ *
+ * @param a_fLocked For the windows shared folders workarounds.
+ *
+ * @remarks Disabled the PageList feature for locked memory on Windows,
+ * because a new MDL is created by VBGL to get the page addresses
+ * and the pages from the MDL are marked as dirty when they should not.
+ */
+#if defined(RT_OS_WINDOWS)
+# define VBGLR0_CAN_USE_PHYS_PAGE_LIST(a_fLocked) \
+ ( !(a_fLocked) && (g_vbgldata.hostVersion.features & VMMDEV_HVF_HGCM_PHYS_PAGE_LIST) )
+#else
+# define VBGLR0_CAN_USE_PHYS_PAGE_LIST(a_fLocked) \
+ ( !!(g_vbgldata.hostVersion.features & VMMDEV_HVF_HGCM_PHYS_PAGE_LIST) )
+#endif
+
+int vbglR0Enter (void);
+
+#ifdef VBOX_WITH_HGCM
+# ifndef VBGL_VBOXGUEST
+int vbglR0HGCMInit(void);
+int vbglR0HGCMTerminate(void);
+# endif
+struct VBGLHGCMHANDLEDATA *vbglHGCMHandleAlloc(void);
+void vbglHGCMHandleFree(struct VBGLHGCMHANDLEDATA *pHandle);
+#endif /* VBOX_WITH_HGCM */
+
+#ifndef VBGL_VBOXGUEST
+/**
+ * Get a handle to the main VBoxGuest driver.
+ * @returns VERR_TRY_AGAIN if the main driver has not yet been loaded.
+ */
+int vbglGetDriver(VBGLDRIVER **ppDriver);
+#endif
+
+#endif /* !___VBoxGuestLib_VBGLInternal_h */
+
--- /dev/null
+/* $Id: log-vbox.cpp $ */
+/** @file
+ * VirtualBox Runtime - Logging configuration.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+/** @page pg_rtlog Runtime - Logging
+ *
+ * VBox uses the IPRT logging system which supports group level flags and multiple
+ * destinations. The GC logging is making it even more interesting since GC logging will
+ * have to be buffered and written when back in host context.
+ *
+ * [more later]
+ *
+ *
+ * @section sec_logging_destination The Destination Specifier.
+ *
+ * The {logger-env-base}_DEST environment variable can be used to specify where
+ * the log output goes. The following specifiers are recognized:
+ *
+ * - file=\<filename\>
+ * This sets the logger output filename to \<filename\>. Not formatting
+ * or anything is supported. Each logger specifies a default name if
+ * file logging should be enabled by default.
+ *
+ * - nofile
+ * This disables the file output.
+ *
+ * - stdout
+ * Enables logger output to stdout.
+ *
+ * - nostdout
+ * Disables logger output to stdout.
+ *
+ * - stderr
+ * Enables logger output to stderr.
+ *
+ * - nostderr
+ * Disables logger output to stderr.
+ *
+ * - debugger
+ * Enables logger output to native debugger. (Win32/64 only)
+ *
+ * - nodebugger
+ * Disables logger output to native debugger. (Win32/64 only)
+ *
+ * - user
+ * Enables logger output to special backdoor if in guest r0.
+ *
+ * - nodebugger
+ * Disables logger output to special user stream.
+ *
+ *
+ *
+ * @section sec_logging_group The Group Specifier.
+ *
+ * The {logger-env-base} environment variable can be used to specify which
+ * logger groups to enable and which to disable. By default all groups are
+ * disabled. For your convenience this specifier is case in-sensitive (ASCII).
+ *
+ * The specifier is evaluated from left to right.
+ *
+ * [more later]
+ *
+ * The groups settings can be reprogrammed during execution using the
+ * RTLogGroupSettings() command and a group specifier.
+ *
+ *
+ *
+ * @section sec_logging_default The Default Logger
+ *
+ * The default logger uses VBOX_LOG_DEST as destination specifier. File output is
+ * enabled by default and goes to a file "./VBox-\<pid\>.log".
+ *
+ * The default logger have all groups turned off by default to force the developer
+ * to be careful with what log information to collect - logging everything is
+ * generally NOT a good idea.
+ *
+ * The log groups of the default logger can be found in the LOGGROUP in enum. The
+ * VBOX_LOG environment variable and the .log debugger command can be used to
+ * configure the groups.
+ *
+ * Each group have flags in addition to the enable/disable flag. These flags can
+ * be appended to the group name using dot separators. The flags correspond to
+ * RTLOGGRPFLAGS and have a short and a long version:
+ *
+ * - e - Enabled: Whether the group is enabled at all.
+ * - l - Level2: Level-2 logging.
+ * - f - Flow: Execution flow logging (entry messages)
+ * - s - Sander: Special Sander logging messages.
+ * - b - Bird: Special Bird logging messages.
+ *
+ * @todo Update this section...
+ *
+ * Example:
+ *
+ * VBOX_LOG=+all+pgm.e.s.b.z.l-qemu
+ *
+ * Space and ';' separators are allowed:
+ *
+ * VBOX_LOG=+all +pgm.e.s.b.z.l ; - qemu
+ *
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#ifdef IN_RING3
+# if defined(RT_OS_WINDOWS)
+# include <iprt/win/windows.h>
+# elif defined(RT_OS_LINUX)
+# include <unistd.h>
+# elif defined(RT_OS_FREEBSD) || defined(RT_OS_NETBSD)
+# include <sys/param.h>
+# include <sys/sysctl.h>
+# if defined(RT_OS_FREEBSD)
+# include <sys/user.h>
+# endif
+# include <stdlib.h>
+# include <unistd.h>
+# elif defined(RT_OS_HAIKU)
+# include <OS.h>
+# elif defined(RT_OS_SOLARIS)
+# define _STRUCTURED_PROC 1
+# undef _FILE_OFFSET_BITS /* procfs doesn't like this */
+# include <sys/procfs.h>
+# include <unistd.h>
+# elif defined(RT_OS_OS2)
+# include <stdlib.h>
+# endif
+#endif
+
+#include <VBox/log.h>
+#include <iprt/asm.h>
+#include <iprt/err.h>
+#include <iprt/time.h>
+#ifdef IN_RING3
+# include <iprt/param.h>
+# include <iprt/assert.h>
+# include <iprt/path.h>
+# include <iprt/process.h>
+# include <iprt/string.h>
+# include <iprt/mem.h>
+# include <stdio.h>
+#endif
+#if defined(IN_RING0) && defined(RT_OS_DARWIN)
+# include <iprt/asm-amd64-x86.h>
+# include <iprt/thread.h>
+#endif
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/** The default logger. */
+static PRTLOGGER g_pLogger = NULL;
+/** The default logger groups.
+ * This must match LOGGROUP! */
+static const char *g_apszGroups[] =
+VBOX_LOGGROUP_NAMES;
+
+
+/**
+ * Creates the default logger instance for a VBox process.
+ *
+ * @returns Pointer to the logger instance.
+ */
+RTDECL(PRTLOGGER) RTLogDefaultInit(void)
+{
+ /*
+ * Initialize the default logger instance.
+ * Take care to do this once and not recursively.
+ */
+ static volatile uint32_t fInitializing = 0;
+ PRTLOGGER pLogger;
+ int rc;
+
+ if (g_pLogger || !ASMAtomicCmpXchgU32(&fInitializing, 1, 0))
+ return g_pLogger;
+
+#ifdef IN_RING3
+ /*
+ * Assert the group definitions.
+ */
+#define ASSERT_LOG_GROUP(grp) ASSERT_LOG_GROUP2(LOG_GROUP_##grp, #grp)
+#define ASSERT_LOG_GROUP2(def, str) \
+ do { if (strcmp(g_apszGroups[def], str)) {printf("%s='%s' expects '%s'\n", #def, g_apszGroups[def], str); RTAssertDoPanic(); } } while (0)
+ ASSERT_LOG_GROUP(DEFAULT);
+ ASSERT_LOG_GROUP(AUDIO_MIXER);
+ ASSERT_LOG_GROUP(AUDIO_MIXER_BUFFER);
+ ASSERT_LOG_GROUP(AUTOLOGON);
+ ASSERT_LOG_GROUP(CFGM);
+ ASSERT_LOG_GROUP(CPUM);
+ ASSERT_LOG_GROUP(CSAM);
+ ASSERT_LOG_GROUP(DBGC);
+ ASSERT_LOG_GROUP(DBGF);
+ ASSERT_LOG_GROUP(DBGF_INFO);
+ ASSERT_LOG_GROUP(DBGG);
+ ASSERT_LOG_GROUP(DEV);
+ ASSERT_LOG_GROUP(DEV_AC97);
+ ASSERT_LOG_GROUP(DEV_ACPI);
+ ASSERT_LOG_GROUP(DEV_APIC);
+ ASSERT_LOG_GROUP(DEV_BUSLOGIC);
+ ASSERT_LOG_GROUP(DEV_DMA);
+ ASSERT_LOG_GROUP(DEV_E1000);
+ ASSERT_LOG_GROUP(DEV_EFI);
+ ASSERT_LOG_GROUP(DEV_EHCI);
+ ASSERT_LOG_GROUP(DEV_FDC);
+ ASSERT_LOG_GROUP(DEV_GIM);
+ ASSERT_LOG_GROUP(DEV_HDA);
+ ASSERT_LOG_GROUP(DEV_HDA_CODEC);
+ ASSERT_LOG_GROUP(DEV_HPET);
+ ASSERT_LOG_GROUP(DEV_IDE);
+ ASSERT_LOG_GROUP(DEV_INIP);
+ ASSERT_LOG_GROUP(DEV_KBD);
+ ASSERT_LOG_GROUP(DEV_LPC);
+ ASSERT_LOG_GROUP(DEV_LSILOGICSCSI);
+ ASSERT_LOG_GROUP(DEV_NVME);
+ ASSERT_LOG_GROUP(DEV_OHCI);
+ ASSERT_LOG_GROUP(DEV_PARALLEL);
+ ASSERT_LOG_GROUP(DEV_PC);
+ ASSERT_LOG_GROUP(DEV_PC_ARCH);
+ ASSERT_LOG_GROUP(DEV_PC_BIOS);
+ ASSERT_LOG_GROUP(DEV_PCI);
+ ASSERT_LOG_GROUP(DEV_PCI_RAW);
+ ASSERT_LOG_GROUP(DEV_PCNET);
+ ASSERT_LOG_GROUP(DEV_PIC);
+ ASSERT_LOG_GROUP(DEV_PIT);
+ ASSERT_LOG_GROUP(DEV_RTC);
+ ASSERT_LOG_GROUP(DEV_SB16);
+ ASSERT_LOG_GROUP(DEV_SERIAL);
+ ASSERT_LOG_GROUP(DEV_SMC);
+ ASSERT_LOG_GROUP(DEV_VGA);
+ ASSERT_LOG_GROUP(DEV_VIRTIO);
+ ASSERT_LOG_GROUP(DEV_VIRTIO_NET);
+ ASSERT_LOG_GROUP(DEV_VMM);
+ ASSERT_LOG_GROUP(DEV_VMM_BACKDOOR);
+ ASSERT_LOG_GROUP(DEV_VMM_STDERR);
+ ASSERT_LOG_GROUP(DEV_VMSVGA);
+ ASSERT_LOG_GROUP(DEV_XHCI);
+ ASSERT_LOG_GROUP(DIS);
+ ASSERT_LOG_GROUP(DRV);
+ ASSERT_LOG_GROUP(DRV_ACPI);
+ ASSERT_LOG_GROUP(DRV_AUDIO);
+ ASSERT_LOG_GROUP(DRV_BLOCK);
+ ASSERT_LOG_GROUP(DRV_CHAR);
+ ASSERT_LOG_GROUP(DRV_DISK_INTEGRITY);
+ ASSERT_LOG_GROUP(DRV_DISPLAY);
+ ASSERT_LOG_GROUP(DRV_FLOPPY);
+ ASSERT_LOG_GROUP(DRV_HOST_AUDIO);
+ ASSERT_LOG_GROUP(DRV_HOST_BASE);
+ ASSERT_LOG_GROUP(DRV_HOST_DVD);
+ ASSERT_LOG_GROUP(DRV_HOST_FLOPPY);
+ ASSERT_LOG_GROUP(DRV_HOST_PARALLEL);
+ ASSERT_LOG_GROUP(DRV_HOST_SERIAL);
+ ASSERT_LOG_GROUP(DRV_INTNET);
+ ASSERT_LOG_GROUP(DRV_ISO);
+ ASSERT_LOG_GROUP(DRV_KBD_QUEUE);
+ ASSERT_LOG_GROUP(DRV_LWIP);
+ ASSERT_LOG_GROUP(DRV_MINIPORT);
+ ASSERT_LOG_GROUP(DRV_MOUSE_QUEUE);
+ ASSERT_LOG_GROUP(DRV_NAMEDPIPE);
+ ASSERT_LOG_GROUP(DRV_NAT);
+ ASSERT_LOG_GROUP(DRV_RAW_IMAGE);
+ ASSERT_LOG_GROUP(DRV_SCSI);
+ ASSERT_LOG_GROUP(DRV_SCSIHOST);
+ ASSERT_LOG_GROUP(DRV_TCP);
+ ASSERT_LOG_GROUP(DRV_TRANSPORT_ASYNC);
+ ASSERT_LOG_GROUP(DRV_TUN);
+ ASSERT_LOG_GROUP(DRV_UDPTUNNEL);
+ ASSERT_LOG_GROUP(DRV_USBPROXY);
+ ASSERT_LOG_GROUP(DRV_VBOXHDD);
+ ASSERT_LOG_GROUP(DRV_VD);
+ ASSERT_LOG_GROUP(DRV_VRDE_AUDIO);
+ ASSERT_LOG_GROUP(DRV_VSWITCH);
+ ASSERT_LOG_GROUP(DRV_VUSB);
+ ASSERT_LOG_GROUP(EM);
+ ASSERT_LOG_GROUP(FTM);
+ ASSERT_LOG_GROUP(GIM);
+ ASSERT_LOG_GROUP(GMM);
+ ASSERT_LOG_GROUP(GUEST_CONTROL);
+ ASSERT_LOG_GROUP(GUEST_DND);
+ ASSERT_LOG_GROUP(GUI);
+ ASSERT_LOG_GROUP(GVMM);
+ ASSERT_LOG_GROUP(HGCM);
+ ASSERT_LOG_GROUP(HGSMI);
+ ASSERT_LOG_GROUP(HM);
+ ASSERT_LOG_GROUP(IEM);
+ ASSERT_LOG_GROUP(IOM);
+ ASSERT_LOG_GROUP(IPC);
+ ASSERT_LOG_GROUP(LWIP);
+ ASSERT_LOG_GROUP(LWIP_API_LIB);
+ ASSERT_LOG_GROUP(LWIP_API_MSG);
+ ASSERT_LOG_GROUP(LWIP_ETHARP);
+ ASSERT_LOG_GROUP(LWIP_ICMP);
+ ASSERT_LOG_GROUP(LWIP_IGMP);
+ ASSERT_LOG_GROUP(LWIP_INET);
+ ASSERT_LOG_GROUP(LWIP_IP4);
+ ASSERT_LOG_GROUP(LWIP_IP4_REASS);
+ ASSERT_LOG_GROUP(LWIP_IP6);
+ ASSERT_LOG_GROUP(LWIP_MEM);
+ ASSERT_LOG_GROUP(LWIP_MEMP);
+ ASSERT_LOG_GROUP(LWIP_NETIF);
+ ASSERT_LOG_GROUP(LWIP_PBUF);
+ ASSERT_LOG_GROUP(LWIP_RAW);
+ ASSERT_LOG_GROUP(LWIP_SOCKETS);
+ ASSERT_LOG_GROUP(LWIP_SYS);
+ ASSERT_LOG_GROUP(LWIP_TCP);
+ ASSERT_LOG_GROUP(LWIP_TCPIP);
+ ASSERT_LOG_GROUP(LWIP_TCP_CWND);
+ ASSERT_LOG_GROUP(LWIP_TCP_FR);
+ ASSERT_LOG_GROUP(LWIP_TCP_INPUT);
+ ASSERT_LOG_GROUP(LWIP_TCP_OUTPUT);
+ ASSERT_LOG_GROUP(LWIP_TCP_QLEN);
+ ASSERT_LOG_GROUP(LWIP_TCP_RST);
+ ASSERT_LOG_GROUP(LWIP_TCP_RTO);
+ ASSERT_LOG_GROUP(LWIP_TCP_WND);
+ ASSERT_LOG_GROUP(LWIP_TIMERS);
+ ASSERT_LOG_GROUP(LWIP_UDP);
+ ASSERT_LOG_GROUP(MAIN);
+ ASSERT_LOG_GROUP(MAIN_ADDITIONSFACILITY);
+ ASSERT_LOG_GROUP(MAIN_ADDITIONSSTATECHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_APPLIANCE);
+ ASSERT_LOG_GROUP(MAIN_AUDIOADAPTER);
+ ASSERT_LOG_GROUP(MAIN_BANDWIDTHCONTROL);
+ ASSERT_LOG_GROUP(MAIN_BANDWIDTHGROUP);
+ ASSERT_LOG_GROUP(MAIN_BANDWIDTHGROUPCHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_BIOSSETTINGS);
+ ASSERT_LOG_GROUP(MAIN_CANSHOWWINDOWEVENT);
+ ASSERT_LOG_GROUP(MAIN_CLIPBOARDMODECHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_CONSOLE);
+ ASSERT_LOG_GROUP(MAIN_CPUCHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_CPUEXECUTIONCAPCHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_DHCPSERVER);
+ ASSERT_LOG_GROUP(MAIN_DIRECTORY);
+ ASSERT_LOG_GROUP(MAIN_DISPLAY);
+ ASSERT_LOG_GROUP(MAIN_DISPLAYSOURCEBITMAP);
+ ASSERT_LOG_GROUP(MAIN_DNDBASE);
+ ASSERT_LOG_GROUP(MAIN_DNDMODECHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_DNDSOURCE);
+ ASSERT_LOG_GROUP(MAIN_DNDTARGET);
+ ASSERT_LOG_GROUP(MAIN_EMULATEDUSB);
+ ASSERT_LOG_GROUP(MAIN_EVENT);
+ ASSERT_LOG_GROUP(MAIN_EVENTLISTENER);
+ ASSERT_LOG_GROUP(MAIN_EVENTSOURCE);
+ ASSERT_LOG_GROUP(MAIN_EVENTSOURCECHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_EXTPACK);
+ ASSERT_LOG_GROUP(MAIN_EXTPACKBASE);
+ ASSERT_LOG_GROUP(MAIN_EXTPACKFILE);
+ ASSERT_LOG_GROUP(MAIN_EXTPACKMANAGER);
+ ASSERT_LOG_GROUP(MAIN_EXTPACKPLUGIN);
+ ASSERT_LOG_GROUP(MAIN_EXTRADATACANCHANGEEVENT);
+ ASSERT_LOG_GROUP(MAIN_EXTRADATACHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_FILE);
+ ASSERT_LOG_GROUP(MAIN_FRAMEBUFFER);
+ ASSERT_LOG_GROUP(MAIN_FRAMEBUFFEROVERLAY);
+ ASSERT_LOG_GROUP(MAIN_FSOBJINFO);
+ ASSERT_LOG_GROUP(MAIN_GUEST);
+ ASSERT_LOG_GROUP(MAIN_GUESTDIRECTORY);
+ ASSERT_LOG_GROUP(MAIN_GUESTDNDSOURCE);
+ ASSERT_LOG_GROUP(MAIN_GUESTDNDTARGET);
+ ASSERT_LOG_GROUP(MAIN_GUESTERRORINFO);
+ ASSERT_LOG_GROUP(MAIN_GUESTFILE);
+ ASSERT_LOG_GROUP(MAIN_GUESTFILEEVENT);
+ ASSERT_LOG_GROUP(MAIN_GUESTFILEIOEVENT);
+ ASSERT_LOG_GROUP(MAIN_GUESTFILEOFFSETCHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_GUESTFILEREADEVENT);
+ ASSERT_LOG_GROUP(MAIN_GUESTFILEREGISTEREDEVENT);
+ ASSERT_LOG_GROUP(MAIN_GUESTFILESTATECHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_GUESTFILEWRITEEVENT);
+ ASSERT_LOG_GROUP(MAIN_GUESTFSOBJINFO);
+ ASSERT_LOG_GROUP(MAIN_GUESTKEYBOARDEVENT);
+ ASSERT_LOG_GROUP(MAIN_GUESTMONITORCHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_GUESTMOUSEEVENT);
+ ASSERT_LOG_GROUP(MAIN_GUESTMULTITOUCHEVENT);
+ ASSERT_LOG_GROUP(MAIN_GUESTOSTYPE);
+ ASSERT_LOG_GROUP(MAIN_GUESTPROCESS);
+ ASSERT_LOG_GROUP(MAIN_GUESTPROCESSEVENT);
+ ASSERT_LOG_GROUP(MAIN_GUESTPROCESSINPUTNOTIFYEVENT);
+ ASSERT_LOG_GROUP(MAIN_GUESTPROCESSIOEVENT);
+ ASSERT_LOG_GROUP(MAIN_GUESTPROCESSOUTPUTEVENT);
+ ASSERT_LOG_GROUP(MAIN_GUESTPROCESSREGISTEREDEVENT);
+ ASSERT_LOG_GROUP(MAIN_GUESTPROCESSSTATECHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_GUESTPROPERTYCHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_GUESTSESSION);
+ ASSERT_LOG_GROUP(MAIN_GUESTSESSIONEVENT);
+ ASSERT_LOG_GROUP(MAIN_GUESTSESSIONREGISTEREDEVENT);
+ ASSERT_LOG_GROUP(MAIN_GUESTSESSIONSTATECHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_GUESTUSERSTATECHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_HOST);
+ ASSERT_LOG_GROUP(MAIN_HOSTNAMERESOLUTIONCONFIGURATIONCHANGEEVENT);
+ ASSERT_LOG_GROUP(MAIN_HOSTNETWORKINTERFACE);
+ ASSERT_LOG_GROUP(MAIN_HOSTPCIDEVICEPLUGEVENT);
+ ASSERT_LOG_GROUP(MAIN_HOSTUSBDEVICE);
+ ASSERT_LOG_GROUP(MAIN_HOSTUSBDEVICEFILTER);
+ ASSERT_LOG_GROUP(MAIN_HOSTVIDEOINPUTDEVICE);
+ ASSERT_LOG_GROUP(MAIN_INTERNALMACHINECONTROL);
+ ASSERT_LOG_GROUP(MAIN_INTERNALSESSIONCONTROL);
+ ASSERT_LOG_GROUP(MAIN_KEYBOARD);
+ ASSERT_LOG_GROUP(MAIN_KEYBOARDLEDSCHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_MACHINE);
+ ASSERT_LOG_GROUP(MAIN_MACHINEDATACHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_MACHINEDEBUGGER);
+ ASSERT_LOG_GROUP(MAIN_MACHINEEVENT);
+ ASSERT_LOG_GROUP(MAIN_MACHINEREGISTEREDEVENT);
+ ASSERT_LOG_GROUP(MAIN_MACHINESTATECHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_MEDIUM);
+ ASSERT_LOG_GROUP(MAIN_MEDIUMATTACHMENT);
+ ASSERT_LOG_GROUP(MAIN_MEDIUMCHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_MEDIUMCONFIGCHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_MEDIUMFORMAT);
+ ASSERT_LOG_GROUP(MAIN_MEDIUMREGISTEREDEVENT);
+ ASSERT_LOG_GROUP(MAIN_MOUSE);
+ ASSERT_LOG_GROUP(MAIN_MOUSECAPABILITYCHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_MOUSEPOINTERSHAPE);
+ ASSERT_LOG_GROUP(MAIN_MOUSEPOINTERSHAPECHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_NATENGINE);
+ ASSERT_LOG_GROUP(MAIN_NATNETWORK);
+ ASSERT_LOG_GROUP(MAIN_NATNETWORKALTEREVENT);
+ ASSERT_LOG_GROUP(MAIN_NATNETWORKCHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_NATNETWORKCREATIONDELETIONEVENT);
+ ASSERT_LOG_GROUP(MAIN_NATNETWORKPORTFORWARDEVENT);
+ ASSERT_LOG_GROUP(MAIN_NATNETWORKSETTINGEVENT);
+ ASSERT_LOG_GROUP(MAIN_NATNETWORKSTARTSTOPEVENT);
+ ASSERT_LOG_GROUP(MAIN_NATREDIRECTEVENT);
+ ASSERT_LOG_GROUP(MAIN_NETWORKADAPTER);
+ ASSERT_LOG_GROUP(MAIN_NETWORKADAPTERCHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_PARALLELPORT);
+ ASSERT_LOG_GROUP(MAIN_PARALLELPORTCHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_PCIADDRESS);
+ ASSERT_LOG_GROUP(MAIN_PCIDEVICEATTACHMENT);
+ ASSERT_LOG_GROUP(MAIN_PERFORMANCECOLLECTOR);
+ ASSERT_LOG_GROUP(MAIN_PERFORMANCEMETRIC);
+ ASSERT_LOG_GROUP(MAIN_PROCESS);
+ ASSERT_LOG_GROUP(MAIN_PROGRESS);
+ ASSERT_LOG_GROUP(MAIN_REUSABLEEVENT);
+ ASSERT_LOG_GROUP(MAIN_RUNTIMEERROREVENT);
+ ASSERT_LOG_GROUP(MAIN_SERIALPORT);
+ ASSERT_LOG_GROUP(MAIN_SERIALPORTCHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_SESSION);
+ ASSERT_LOG_GROUP(MAIN_SESSIONSTATECHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_SHAREDFOLDER);
+ ASSERT_LOG_GROUP(MAIN_SHAREDFOLDERCHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_SHOWWINDOWEVENT);
+ ASSERT_LOG_GROUP(MAIN_SNAPSHOT);
+ ASSERT_LOG_GROUP(MAIN_SNAPSHOTCHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_SNAPSHOTDELETEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_SNAPSHOTEVENT);
+ ASSERT_LOG_GROUP(MAIN_SNAPSHOTRESTOREDEVENT);
+ ASSERT_LOG_GROUP(MAIN_SNAPSHOTTAKENEVENT);
+ ASSERT_LOG_GROUP(MAIN_STATECHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_STORAGECONTROLLER);
+ ASSERT_LOG_GROUP(MAIN_STORAGECONTROLLERCHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_STORAGEDEVICECHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_SYSTEMPROPERTIES);
+ ASSERT_LOG_GROUP(MAIN_TOKEN);
+ ASSERT_LOG_GROUP(MAIN_USBCONTROLLER);
+ ASSERT_LOG_GROUP(MAIN_USBCONTROLLERCHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_USBDEVICE);
+ ASSERT_LOG_GROUP(MAIN_USBDEVICEFILTERS);
+ ASSERT_LOG_GROUP(MAIN_USBDEVICESTATECHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_VBOXSVCAVAILABILITYCHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_VIRTUALBOX);
+ ASSERT_LOG_GROUP(MAIN_VIRTUALBOXCLIENT);
+ ASSERT_LOG_GROUP(MAIN_VIRTUALSYSTEMDESCRIPTION);
+ ASSERT_LOG_GROUP(MAIN_VRDESERVER);
+ ASSERT_LOG_GROUP(MAIN_VRDESERVERCHANGEDEVENT);
+ ASSERT_LOG_GROUP(MAIN_VRDESERVERINFO);
+ ASSERT_LOG_GROUP(MAIN_VRDESERVERINFOCHANGEDEVENT);
+ ASSERT_LOG_GROUP(MISC);
+ ASSERT_LOG_GROUP(MM);
+ ASSERT_LOG_GROUP(MM_HEAP);
+ ASSERT_LOG_GROUP(MM_HYPER);
+ ASSERT_LOG_GROUP(MM_HYPER_HEAP);
+ ASSERT_LOG_GROUP(MM_PHYS);
+ ASSERT_LOG_GROUP(MM_POOL);
+ ASSERT_LOG_GROUP(NAT_SERVICE);
+ ASSERT_LOG_GROUP(NET_ADP_DRV);
+ ASSERT_LOG_GROUP(NET_FLT_DRV);
+ ASSERT_LOG_GROUP(NET_SERVICE);
+ ASSERT_LOG_GROUP(NET_SHAPER);
+ ASSERT_LOG_GROUP(PATM);
+ ASSERT_LOG_GROUP(PDM);
+ ASSERT_LOG_GROUP(PDM_ASYNC_COMPLETION);
+ ASSERT_LOG_GROUP(PDM_BLK_CACHE);
+ ASSERT_LOG_GROUP(PDM_DEVICE);
+ ASSERT_LOG_GROUP(PDM_DRIVER);
+ ASSERT_LOG_GROUP(PDM_LDR);
+ ASSERT_LOG_GROUP(PDM_QUEUE);
+ ASSERT_LOG_GROUP(PGM);
+ ASSERT_LOG_GROUP(PGM_DYNMAP);
+ ASSERT_LOG_GROUP(PGM_PHYS);
+ ASSERT_LOG_GROUP(PGM_PHYS_ACCESS);
+ ASSERT_LOG_GROUP(PGM_POOL);
+ ASSERT_LOG_GROUP(PGM_SHARED);
+ ASSERT_LOG_GROUP(REM);
+ ASSERT_LOG_GROUP(REM_DISAS);
+ ASSERT_LOG_GROUP(REM_HANDLER);
+ ASSERT_LOG_GROUP(REM_IOPORT);
+ ASSERT_LOG_GROUP(REM_MMIO);
+ ASSERT_LOG_GROUP(REM_PRINTF);
+ ASSERT_LOG_GROUP(REM_RUN);
+ ASSERT_LOG_GROUP(SELM);
+ ASSERT_LOG_GROUP(SHARED_CLIPBOARD);
+ ASSERT_LOG_GROUP(SHARED_CROPENGL);
+ ASSERT_LOG_GROUP(SHARED_FOLDERS);
+ ASSERT_LOG_GROUP(SHARED_OPENGL);
+ ASSERT_LOG_GROUP(SRV_INTNET);
+ ASSERT_LOG_GROUP(SSM);
+ ASSERT_LOG_GROUP(STAM);
+ ASSERT_LOG_GROUP(SUP);
+ ASSERT_LOG_GROUP(TM);
+ ASSERT_LOG_GROUP(TRPM);
+ ASSERT_LOG_GROUP(USB_CARDREADER);
+ ASSERT_LOG_GROUP(USB_DRV);
+ ASSERT_LOG_GROUP(USB_FILTER);
+ ASSERT_LOG_GROUP(USB_KBD);
+ ASSERT_LOG_GROUP(USB_MOUSE);
+ ASSERT_LOG_GROUP(USB_MSD);
+ ASSERT_LOG_GROUP(USB_REMOTE);
+ ASSERT_LOG_GROUP(USB_WEBCAM);
+ ASSERT_LOG_GROUP(VGDRV);
+ ASSERT_LOG_GROUP(VBGL);
+ ASSERT_LOG_GROUP(VD);
+ ASSERT_LOG_GROUP(VD_DMG);
+ ASSERT_LOG_GROUP(VD_ISCSI);
+ ASSERT_LOG_GROUP(VD_PARALLELS);
+ ASSERT_LOG_GROUP(VD_QCOW);
+ ASSERT_LOG_GROUP(VD_QED);
+ ASSERT_LOG_GROUP(VD_RAW);
+ ASSERT_LOG_GROUP(VD_VDI);
+ ASSERT_LOG_GROUP(VD_VHD);
+ ASSERT_LOG_GROUP(VD_VHDX);
+ ASSERT_LOG_GROUP(VD_VMDK);
+ ASSERT_LOG_GROUP(VM);
+ ASSERT_LOG_GROUP(VMM);
+ ASSERT_LOG_GROUP(VRDE);
+ ASSERT_LOG_GROUP(VRDP);
+ ASSERT_LOG_GROUP(VSCSI);
+ ASSERT_LOG_GROUP(WEBSERVICE);
+#undef ASSERT_LOG_GROUP
+#undef ASSERT_LOG_GROUP2
+#endif /* IN_RING3 */
+
+ /*
+ * Create the default logging instance.
+ */
+#ifdef IN_RING3
+# ifndef IN_GUEST
+ char szExecName[RTPATH_MAX];
+ if (!RTProcGetExecutablePath(szExecName, sizeof(szExecName)))
+ strcpy(szExecName, "VBox");
+ RTTIMESPEC TimeSpec;
+ RTTIME Time;
+ RTTimeExplode(&Time, RTTimeNow(&TimeSpec));
+ rc = RTLogCreate(&pLogger, 0, NULL, "VBOX_LOG", RT_ELEMENTS(g_apszGroups), &g_apszGroups[0], RTLOGDEST_FILE,
+ "./%04d-%02d-%02d-%02d-%02d-%02d.%03d-%s-%d.log",
+ Time.i32Year, Time.u8Month, Time.u8MonthDay, Time.u8Hour, Time.u8Minute, Time.u8Second, Time.u32Nanosecond / 10000000,
+ RTPathFilename(szExecName), RTProcSelf());
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Write a log header.
+ */
+ char szBuf[RTPATH_MAX];
+ RTTimeSpecToString(&TimeSpec, szBuf, sizeof(szBuf));
+ RTLogLoggerEx(pLogger, 0, ~0U, "Log created: %s\n", szBuf);
+ RTLogLoggerEx(pLogger, 0, ~0U, "Executable: %s\n", szExecName);
+
+ /* executable and arguments - tricky and all platform specific. */
+# if defined(RT_OS_WINDOWS)
+ RTLogLoggerEx(pLogger, 0, ~0U, "Commandline: %ls\n", GetCommandLineW());
+
+# elif defined(RT_OS_SOLARIS)
+ psinfo_t psi;
+ char szArgFileBuf[80];
+ RTStrPrintf(szArgFileBuf, sizeof(szArgFileBuf), "/proc/%ld/psinfo", (long)getpid());
+ FILE* pFile = fopen(szArgFileBuf, "rb");
+ if (pFile)
+ {
+ if (fread(&psi, sizeof(psi), 1, pFile) == 1)
+ {
+# if 0 /* 100% safe:*/
+ RTLogLoggerEx(pLogger, 0, ~0U, "Args: %s\n", psi.pr_psargs);
+# else /* probably safe: */
+ const char * const *argv = (const char * const *)psi.pr_argv;
+ for (int iArg = 0; iArg < psi.pr_argc; iArg++)
+ RTLogLoggerEx(pLogger, 0, ~0U, "Arg[%d]: %s\n", iArg, argv[iArg]);
+# endif
+
+ }
+ fclose(pFile);
+ }
+
+# elif defined(RT_OS_LINUX)
+ FILE *pFile = fopen("/proc/self/cmdline", "r");
+ if (pFile)
+ {
+ /* braindead */
+ unsigned iArg = 0;
+ int ch;
+ bool fNew = true;
+ while (!feof(pFile) && (ch = fgetc(pFile)) != EOF)
+ {
+ if (fNew)
+ {
+ RTLogLoggerEx(pLogger, 0, ~0U, "Arg[%u]: ", iArg++);
+ fNew = false;
+ }
+ if (ch)
+ RTLogLoggerEx(pLogger, 0, ~0U, "%c", ch);
+ else
+ {
+ RTLogLoggerEx(pLogger, 0, ~0U, "\n");
+ fNew = true;
+ }
+ }
+ if (!fNew)
+ RTLogLoggerEx(pLogger, 0, ~0U, "\n");
+ fclose(pFile);
+ }
+
+# elif defined(RT_OS_HAIKU)
+ team_info info;
+ if (get_team_info(0, &info) == B_OK)
+ {
+ /* there is an info.argc, but no way to know arg boundaries */
+ RTLogLoggerEx(pLogger, 0, ~0U, "Commandline: %.64s\n", info.args);
+ }
+
+# elif defined(RT_OS_FREEBSD) || defined(RT_OS_NETBSD)
+ /* Retrieve the required length first */
+ int aiName[4];
+# if defined(RT_OS_FREEBSD)
+ aiName[0] = CTL_KERN;
+ aiName[1] = KERN_PROC;
+ aiName[2] = KERN_PROC_ARGS; /* Introduced in FreeBSD 4.0 */
+ aiName[3] = getpid();
+# elif defined(RT_OS_NETBSD)
+ aiName[0] = CTL_KERN;
+ aiName[1] = KERN_PROC_ARGS;
+ aiName[2] = getpid();
+ aiName[3] = KERN_PROC_ARGV;
+# endif
+ size_t cchArgs = 0;
+ int rcBSD = sysctl(aiName, RT_ELEMENTS(aiName), NULL, &cchArgs, NULL, 0);
+ if (cchArgs > 0)
+ {
+ char *pszArgFileBuf = (char *)RTMemAllocZ(cchArgs + 1 /* Safety */);
+ if (pszArgFileBuf)
+ {
+ /* Retrieve the argument list */
+ rcBSD = sysctl(aiName, RT_ELEMENTS(aiName), pszArgFileBuf, &cchArgs, NULL, 0);
+ if (!rcBSD)
+ {
+ unsigned iArg = 0;
+ size_t off = 0;
+ while (off < cchArgs)
+ {
+ size_t cchArg = strlen(&pszArgFileBuf[off]);
+ RTLogLoggerEx(pLogger, 0, ~0U, "Arg[%u]: %s\n", iArg, &pszArgFileBuf[off]);
+
+ /* advance */
+ off += cchArg + 1;
+ iArg++;
+ }
+ }
+ RTMemFree(pszArgFileBuf);
+ }
+ }
+
+# elif defined(RT_OS_OS2) || defined(RT_OS_DARWIN)
+ /* commandline? */
+# else
+# error needs porting.
+# endif
+ }
+
+# else /* IN_GUEST */
+ /* The user destination is backdoor logging. */
+ rc = RTLogCreate(&pLogger, 0, NULL, "VBOX_LOG", RT_ELEMENTS(g_apszGroups), &g_apszGroups[0], RTLOGDEST_USER, "VBox.log");
+# endif /* IN_GUEST */
+
+#else /* IN_RING0 */
+
+ /* Some platforms has trouble allocating memory with interrupts and/or
+ preemption disabled. Check and fail before we panic. */
+# if defined(RT_OS_DARWIN)
+ if ( !ASMIntAreEnabled()
+ || !RTThreadPreemptIsEnabled(NIL_RTTHREAD))
+ return NULL;
+# endif
+
+# ifndef IN_GUEST
+ rc = RTLogCreate(&pLogger, 0, NULL, "VBOX_LOG", RT_ELEMENTS(g_apszGroups), &g_apszGroups[0], RTLOGDEST_FILE, "VBox-ring0.log");
+# else /* IN_GUEST */
+ rc = RTLogCreate(&pLogger, 0, NULL, "VBOX_LOG", RT_ELEMENTS(g_apszGroups), &g_apszGroups[0], RTLOGDEST_USER, "VBox-ring0.log");
+# endif /* IN_GUEST */
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * This is where you set your ring-0 logging preferences.
+ *
+ * On platforms which don't differ between debugger and kernel
+ * log printing, STDOUT is gonna be a stub and the DEBUGGER
+ * destination is the one doing all the work. On platforms
+ * that do differ (like Darwin), STDOUT is the kernel log.
+ */
+# if defined(DEBUG_bird)
+ /*RTLogGroupSettings(pLogger, "all=~0 -default.l6.l5.l4.l3");*/
+ RTLogFlags(pLogger, "enabled unbuffered pid tid");
+# ifndef IN_GUEST
+ pLogger->fDestFlags |= RTLOGDEST_DEBUGGER | RTLOGDEST_STDOUT;
+# else
+ RTLogGroupSettings(pLogger, "all=~0 -default.l6.l5.l4.l3");
+# endif
+# endif
+# if defined(DEBUG_sandervl) && !defined(IN_GUEST)
+ RTLogGroupSettings(pLogger, "+all");
+ RTLogFlags(pLogger, "enabled unbuffered");
+ pLogger->fDestFlags |= RTLOGDEST_DEBUGGER;
+# endif
+# if defined(DEBUG_ramshankar) /* Guest ring-0 as well */
+ RTLogGroupSettings(pLogger, "+all.e.l.f");
+ RTLogFlags(pLogger, "enabled unbuffered");
+ pLogger->fDestFlags |= RTLOGDEST_DEBUGGER;
+# endif
+# if defined(DEBUG_aleksey) /* Guest ring-0 as well */
+ RTLogGroupSettings(pLogger, "net_flt_drv.e.l.f.l3.l4.l5 +net_adp_drv.e.l.f.l3.l4.l5.l6");
+ RTLogFlags(pLogger, "enabled unbuffered");
+ pLogger->fDestFlags |= RTLOGDEST_DEBUGGER | RTLOGDEST_STDOUT;
+# endif
+# if defined(DEBUG_andy) /* Guest ring-0 as well */
+ RTLogGroupSettings(pLogger, "+all.e.l.f");
+ RTLogFlags(pLogger, "enabled unbuffered pid tid");
+ pLogger->fDestFlags |= RTLOGDEST_DEBUGGER | RTLOGDEST_STDOUT;
+# endif
+# if defined(DEBUG_misha) /* Guest ring-0 as well */
+ RTLogFlags(pLogger, "enabled unbuffered");
+ pLogger->fDestFlags |= RTLOGDEST_DEBUGGER;
+# endif
+# if defined(DEBUG_michael) && defined(IN_GUEST)
+ RTLogGroupSettings(pLogger, "+vga.e.l.f");
+ RTLogFlags(pLogger, "enabled unbuffered");
+ pLogger->fDestFlags |= RTLOGDEST_DEBUGGER | RTLOGDEST_STDOUT;
+# endif
+# if 0 /* vboxdrv logging - ATTENTION: this is what we're referring to guys! Change to '# if 1'. */
+ RTLogGroupSettings(pLogger, "all=~0 -default.l6.l5.l4.l3");
+ RTLogFlags(pLogger, "enabled unbuffered tid");
+ pLogger->fDestFlags |= RTLOGDEST_DEBUGGER | RTLOGDEST_STDOUT;
+# endif
+ }
+#endif /* IN_RING0 */
+ return g_pLogger = RT_SUCCESS(rc) ? pLogger : NULL;
+}
--- /dev/null
+/* $Id: logbackdoor.cpp $ */
+/** @file
+ * VirtualBox Runtime - Guest Backdoor Logging.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <VBox/log.h>
+#include "internal/iprt.h"
+#include <iprt/asm-amd64-x86.h>
+#include <iprt/string.h>
+#ifdef IN_GUEST_R3
+# include <VBox/VBoxGuestLib.h>
+#endif
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+static DECLCALLBACK(size_t) rtLogBackdoorOutput(void *pv, const char *pachChars, size_t cbChars);
+
+
+RTDECL(size_t) RTLogBackdoorPrintf(const char *pszFormat, ...)
+{
+ va_list args;
+ size_t cb;
+
+ va_start(args, pszFormat);
+ cb = RTLogBackdoorPrintfV(pszFormat, args);
+ va_end(args);
+
+ return cb;
+}
+
+RT_EXPORT_SYMBOL(RTLogBackdoorPrintf);
+
+
+RTDECL(size_t) RTLogBackdoorPrintfV(const char *pszFormat, va_list args)
+{
+ return RTLogFormatV(rtLogBackdoorOutput, NULL, pszFormat, args);
+}
+
+RT_EXPORT_SYMBOL(RTLogBackdoorPrintfV);
+
+
+/**
+ * Callback for RTLogFormatV which writes to the backdoor.
+ * See PFNRTSTROUTPUT() for details.
+ */
+static DECLCALLBACK(size_t) rtLogBackdoorOutput(void *pvArg, const char *pachChars, size_t cbChars)
+{
+ RT_NOREF_PV(pvArg);
+ RTLogWriteUser(pachChars, cbChars);
+ return cbChars;
+}
+
+
+RTDECL(void) RTLogWriteUser(const char *pch, size_t cb)
+{
+#ifdef IN_GUEST_R3
+ VbglR3WriteLog(pch, cb);
+#else /* !IN_GUEST_R3 */
+ const uint8_t *pau8 = (const uint8_t *)pch;
+ if (cb > 1)
+ ASMOutStrU8(RTLOG_DEBUG_PORT, pau8, cb);
+ else if (cb)
+ ASMOutU8(RTLOG_DEBUG_PORT, *pau8);
+#endif /* !IN_GUEST_R3 */
+}
+
+RT_EXPORT_SYMBOL(RTLogWriteUser);
+
--- /dev/null
+/* $Rev: 109079 $ */
+/** @file
+ * VBoxGuest - Linux specifics.
+ *
+ * Note. Unfortunately, the difference between this and SUPDrv-linux.c is
+ * a little bit too big to be helpful.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_SUP_DRV
+
+#include "the-linux-kernel.h"
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 15)
+# define VBOXGUEST_WITH_INPUT_DRIVER
+#endif
+
+#include "VBoxGuestInternal.h"
+#ifdef VBOXGUEST_WITH_INPUT_DRIVER
+# include <linux/input.h>
+#endif
+#include <linux/miscdevice.h>
+#include <linux/poll.h>
+#include <VBox/version.h>
+#include "revision-generated.h"
+
+#include <iprt/assert.h>
+#include <iprt/asm.h>
+#include <iprt/err.h>
+#include <iprt/initterm.h>
+#include <iprt/mem.h>
+#include <iprt/mp.h>
+#include <iprt/process.h>
+#include <iprt/spinlock.h>
+#include <iprt/semaphore.h>
+#include <VBox/log.h>
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/** The device name. */
+#define DEVICE_NAME "vboxguest"
+/** The device name for the device node open to everyone. */
+#define DEVICE_NAME_USER "vboxuser"
+/** The name of the PCI driver */
+#define DRIVER_NAME DEVICE_NAME
+
+
+/* 2.4.x compatibility macros that may or may not be defined. */
+#ifndef IRQ_RETVAL
+# define irqreturn_t void
+# define IRQ_RETVAL(n)
+#endif
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+static void vgdrvLinuxTermPci(struct pci_dev *pPciDev);
+static int vgdrvLinuxProbePci(struct pci_dev *pPciDev, const struct pci_device_id *id);
+static int vgdrvLinuxModInit(void);
+static void vgdrvLinuxModExit(void);
+static int vgdrvLinuxOpen(struct inode *pInode, struct file *pFilp);
+static int vgdrvLinuxRelease(struct inode *pInode, struct file *pFilp);
+#ifdef HAVE_UNLOCKED_IOCTL
+static long vgdrvLinuxIOCtl(struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
+#else
+static int vgdrvLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
+#endif
+static int vgdrvLinuxFAsync(int fd, struct file *pFile, int fOn);
+static unsigned int vgdrvLinuxPoll(struct file *pFile, poll_table *pPt);
+static ssize_t vgdrvLinuxRead(struct file *pFile, char *pbBuf, size_t cbRead, loff_t *poff);
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/**
+ * Device extention & session data association structure.
+ */
+static VBOXGUESTDEVEXT g_DevExt;
+/** The PCI device. */
+static struct pci_dev *g_pPciDev = NULL;
+/** The base of the I/O port range. */
+static RTIOPORT g_IOPortBase;
+/** The base of the MMIO range. */
+static RTHCPHYS g_MMIOPhysAddr = NIL_RTHCPHYS;
+/** The size of the MMIO range as seen by PCI. */
+static uint32_t g_cbMMIO;
+/** The pointer to the mapping of the MMIO range. */
+static void *g_pvMMIOBase;
+/** Wait queue used by polling. */
+static wait_queue_head_t g_PollEventQueue;
+/** Asynchronous notification stuff. */
+static struct fasync_struct *g_pFAsyncQueue;
+#ifdef VBOXGUEST_WITH_INPUT_DRIVER
+/** Pre-allocated mouse status VMMDev request for use in the IRQ
+ * handler. */
+static VMMDevReqMouseStatus *g_pMouseStatusReq;
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+/** Whether we've create the logger or not. */
+static volatile bool g_fLoggerCreated;
+/** Release logger group settings. */
+static char g_szLogGrp[128];
+/** Release logger flags settings. */
+static char g_szLogFlags[128];
+/** Release logger destination settings. */
+static char g_szLogDst[128];
+# if 0
+/** Debug logger group settings. */
+static char g_szDbgLogGrp[128];
+/** Debug logger flags settings. */
+static char g_szDbgLogFlags[128];
+/** Debug logger destination settings. */
+static char g_szDbgLogDst[128];
+# endif
+#endif
+
+/** The input device handle */
+#ifdef VBOXGUEST_WITH_INPUT_DRIVER
+static struct input_dev *g_pInputDevice = NULL;
+#endif
+
+/** The file_operations structure. */
+static struct file_operations g_FileOps =
+{
+ owner: THIS_MODULE,
+ open: vgdrvLinuxOpen,
+ release: vgdrvLinuxRelease,
+#ifdef HAVE_UNLOCKED_IOCTL
+ unlocked_ioctl: vgdrvLinuxIOCtl,
+#else
+ ioctl: vgdrvLinuxIOCtl,
+#endif
+ fasync: vgdrvLinuxFAsync,
+ read: vgdrvLinuxRead,
+ poll: vgdrvLinuxPoll,
+ llseek: no_llseek,
+};
+
+/** The miscdevice structure. */
+static struct miscdevice g_MiscDevice =
+{
+ minor: MISC_DYNAMIC_MINOR,
+ name: DEVICE_NAME,
+ fops: &g_FileOps,
+};
+
+/** The file_operations structure for the user device.
+ * @remarks For the time being we'll be using the same implementation as
+ * /dev/vboxguest here. */
+static struct file_operations g_FileOpsUser =
+{
+ owner: THIS_MODULE,
+ open: vgdrvLinuxOpen,
+ release: vgdrvLinuxRelease,
+#ifdef HAVE_UNLOCKED_IOCTL
+ unlocked_ioctl: vgdrvLinuxIOCtl,
+#else
+ ioctl: vgdrvLinuxIOCtl,
+#endif
+};
+
+/** The miscdevice structure for the user device. */
+static struct miscdevice g_MiscDeviceUser =
+{
+ minor: MISC_DYNAMIC_MINOR,
+ name: DEVICE_NAME_USER,
+ fops: &g_FileOpsUser,
+};
+
+
+/** PCI hotplug structure. */
+static const struct pci_device_id
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
+__devinitdata
+#endif
+g_VBoxGuestPciId[] =
+{
+ {
+ vendor: VMMDEV_VENDORID,
+ device: VMMDEV_DEVICEID
+ },
+ {
+ /* empty entry */
+ }
+};
+
+MODULE_DEVICE_TABLE(pci, g_VBoxGuestPciId);
+
+/** Structure for registering the PCI driver. */
+static struct pci_driver g_PciDriver =
+{
+ name: DRIVER_NAME,
+ id_table: g_VBoxGuestPciId,
+ probe: vgdrvLinuxProbePci,
+ remove: vgdrvLinuxTermPci
+};
+
+static PVBOXGUESTSESSION g_pKernelSession = NULL;
+
+
+
+/**
+ * Converts a VBox status code to a linux error code.
+ *
+ * @returns corresponding negative linux error code.
+ * @param rc supdrv error code (SUPDRV_ERR_* defines).
+ */
+static int vgdrvLinuxConvertToNegErrno(int rc)
+{
+ if ( rc > -1000
+ && rc < 1000)
+ return -RTErrConvertToErrno(rc);
+ switch (rc)
+ {
+ case VERR_HGCM_SERVICE_NOT_FOUND: return -ESRCH;
+ case VINF_HGCM_CLIENT_REJECTED: return 0;
+ case VERR_HGCM_INVALID_CMD_ADDRESS: return -EFAULT;
+ case VINF_HGCM_ASYNC_EXECUTE: return 0;
+ case VERR_HGCM_INTERNAL: return -EPROTO;
+ case VERR_HGCM_INVALID_CLIENT_ID: return -EINVAL;
+ case VINF_HGCM_SAVE_STATE: return 0;
+ /* No reason to return this to a guest */
+ // case VERR_HGCM_SERVICE_EXISTS: return -EEXIST;
+ default:
+ AssertMsgFailed(("Unhandled error code %Rrc\n", rc));
+ return -EPROTO;
+ }
+}
+
+
+/**
+ * Does the PCI detection and init of the device.
+ *
+ * @returns 0 on success, negated errno on failure.
+ */
+static int vgdrvLinuxProbePci(struct pci_dev *pPciDev, const struct pci_device_id *id)
+{
+ int rc;
+
+ NOREF(id);
+ AssertReturn(!g_pPciDev, -EINVAL);
+ rc = pci_enable_device(pPciDev);
+ if (rc >= 0)
+ {
+ /* I/O Ports are mandatory, the MMIO bit is not. */
+ g_IOPortBase = pci_resource_start(pPciDev, 0);
+ if (g_IOPortBase != 0)
+ {
+ /*
+ * Map the register address space.
+ */
+ g_MMIOPhysAddr = pci_resource_start(pPciDev, 1);
+ g_cbMMIO = pci_resource_len(pPciDev, 1);
+ if (request_mem_region(g_MMIOPhysAddr, g_cbMMIO, DEVICE_NAME) != NULL)
+ {
+ g_pvMMIOBase = ioremap(g_MMIOPhysAddr, g_cbMMIO);
+ if (g_pvMMIOBase)
+ {
+ /** @todo why aren't we requesting ownership of the I/O ports as well? */
+ g_pPciDev = pPciDev;
+ return 0;
+ }
+
+ /* failure cleanup path */
+ LogRel((DEVICE_NAME ": ioremap failed; MMIO Addr=%RHp cb=%#x\n", g_MMIOPhysAddr, g_cbMMIO));
+ rc = -ENOMEM;
+ release_mem_region(g_MMIOPhysAddr, g_cbMMIO);
+ }
+ else
+ {
+ LogRel((DEVICE_NAME ": failed to obtain adapter memory\n"));
+ rc = -EBUSY;
+ }
+ g_MMIOPhysAddr = NIL_RTHCPHYS;
+ g_cbMMIO = 0;
+ g_IOPortBase = 0;
+ }
+ else
+ {
+ LogRel((DEVICE_NAME ": did not find expected hardware resources\n"));
+ rc = -ENXIO;
+ }
+ pci_disable_device(pPciDev);
+ }
+ else
+ LogRel((DEVICE_NAME ": could not enable device: %d\n", rc));
+ return rc;
+}
+
+
+/**
+ * Clean up the usage of the PCI device.
+ */
+static void vgdrvLinuxTermPci(struct pci_dev *pPciDev)
+{
+ g_pPciDev = NULL;
+ if (pPciDev)
+ {
+ iounmap(g_pvMMIOBase);
+ g_pvMMIOBase = NULL;
+
+ release_mem_region(g_MMIOPhysAddr, g_cbMMIO);
+ g_MMIOPhysAddr = NIL_RTHCPHYS;
+ g_cbMMIO = 0;
+
+ pci_disable_device(pPciDev);
+ }
+}
+
+
+/**
+ * Interrupt service routine.
+ *
+ * @returns In 2.4 it returns void.
+ * In 2.6 we indicate whether we've handled the IRQ or not.
+ *
+ * @param iIrq The IRQ number.
+ * @param pvDevId The device ID, a pointer to g_DevExt.
+ * @param pRegs Register set. Removed in 2.6.19.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) && !defined(DOXYGEN_RUNNING)
+static irqreturn_t vgdrvLinuxISR(int iIrq, void *pvDevId)
+#else
+static irqreturn_t vgdrvLinuxISR(int iIrq, void *pvDevId, struct pt_regs *pRegs)
+#endif
+{
+ bool fTaken = VGDrvCommonISR(&g_DevExt);
+ return IRQ_RETVAL(fTaken);
+}
+
+
+/**
+ * Registers the ISR and initializes the poll wait queue.
+ */
+static int __init vgdrvLinuxInitISR(void)
+{
+ int rc;
+
+ init_waitqueue_head(&g_PollEventQueue);
+ rc = request_irq(g_pPciDev->irq,
+ vgdrvLinuxISR,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
+ IRQF_SHARED,
+#else
+ SA_SHIRQ,
+#endif
+ DEVICE_NAME,
+ &g_DevExt);
+ if (rc)
+ {
+ LogRel((DEVICE_NAME ": could not request IRQ %d: err=%d\n", g_pPciDev->irq, rc));
+ return rc;
+ }
+ return 0;
+}
+
+
+/**
+ * Deregisters the ISR.
+ */
+static void vgdrvLinuxTermISR(void)
+{
+ free_irq(g_pPciDev->irq, &g_DevExt);
+}
+
+
+#ifdef VBOXGUEST_WITH_INPUT_DRIVER
+
+/**
+ * Reports the mouse integration status to the host.
+ *
+ * Calls the kernel IOCtl to report mouse status to the host on behalf of
+ * our kernel session.
+ *
+ * @param fStatus The mouse status to report.
+ */
+static int vgdrvLinuxSetMouseStatus(uint32_t fStatus)
+{
+ return VGDrvCommonIoCtl(VBOXGUEST_IOCTL_SET_MOUSE_STATUS, &g_DevExt, g_pKernelSession, &fStatus, sizeof(fStatus), NULL);
+}
+
+
+/**
+ * Called when the input device is first opened.
+ *
+ * Sets up absolute mouse reporting.
+ */
+static int vboxguestOpenInputDevice(struct input_dev *pDev)
+{
+ int rc = vgdrvLinuxSetMouseStatus(VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE | VMMDEV_MOUSE_NEW_PROTOCOL);
+ if (RT_FAILURE(rc))
+ return ENODEV;
+ NOREF(pDev);
+ return 0;
+}
+
+
+/**
+ * Called if all open handles to the input device are closed.
+ *
+ * Disables absolute reporting.
+ */
+static void vboxguestCloseInputDevice(struct input_dev *pDev)
+{
+ NOREF(pDev);
+ vgdrvLinuxSetMouseStatus(0);
+}
+
+
+/**
+ * Creates the kernel input device.
+ */
+static int __init vgdrvLinuxCreateInputDevice(void)
+{
+ int rc = VbglGRAlloc((VMMDevRequestHeader **)&g_pMouseStatusReq, sizeof(*g_pMouseStatusReq), VMMDevReq_GetMouseStatus);
+ if (RT_SUCCESS(rc))
+ {
+ g_pInputDevice = input_allocate_device();
+ if (g_pInputDevice)
+ {
+ g_pInputDevice->id.bustype = BUS_PCI;
+ g_pInputDevice->id.vendor = VMMDEV_VENDORID;
+ g_pInputDevice->id.product = VMMDEV_DEVICEID;
+ g_pInputDevice->id.version = VBOX_SHORT_VERSION;
+ g_pInputDevice->open = vboxguestOpenInputDevice;
+ g_pInputDevice->close = vboxguestCloseInputDevice;
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
+ g_pInputDevice->cdev.dev = &g_pPciDev->dev;
+# else
+ g_pInputDevice->dev.parent = &g_pPciDev->dev;
+# endif
+ rc = input_register_device(g_pInputDevice);
+ if (rc == 0)
+ {
+ /* Do what one of our competitors apparently does as that works. */
+ ASMBitSet(g_pInputDevice->evbit, EV_ABS);
+ ASMBitSet(g_pInputDevice->evbit, EV_KEY);
+# ifdef EV_SYN
+ ASMBitSet(g_pInputDevice->evbit, EV_SYN);
+# endif
+ input_set_abs_params(g_pInputDevice, ABS_X, VMMDEV_MOUSE_RANGE_MIN, VMMDEV_MOUSE_RANGE_MAX, 0, 0);
+ input_set_abs_params(g_pInputDevice, ABS_Y, VMMDEV_MOUSE_RANGE_MIN, VMMDEV_MOUSE_RANGE_MAX, 0, 0);
+ ASMBitSet(g_pInputDevice->keybit, BTN_MOUSE);
+ /** @todo this string should be in a header file somewhere. */
+ g_pInputDevice->name = "VirtualBox mouse integration";
+ return 0;
+ }
+
+ input_free_device(g_pInputDevice);
+ }
+ else
+ rc = -ENOMEM;
+ VbglGRFree(&g_pMouseStatusReq->header);
+ g_pMouseStatusReq = NULL;
+ }
+ else
+ rc = -ENOMEM;
+ return rc;
+}
+
+
+/**
+ * Terminates the kernel input device.
+ */
+static void vgdrvLinuxTermInputDevice(void)
+{
+ VbglGRFree(&g_pMouseStatusReq->header);
+ g_pMouseStatusReq = NULL;
+
+ /* See documentation of input_register_device(): input_free_device()
+ * should not be called after a device has been registered. */
+ input_unregister_device(g_pInputDevice);
+}
+
+#endif /* VBOXGUEST_WITH_INPUT_DRIVER */
+
+
+/**
+ * Creates the device nodes.
+ *
+ * @returns 0 on success, negated errno on failure.
+ */
+static int __init vgdrvLinuxInitDeviceNodes(void)
+{
+ /*
+ * The full feature device node.
+ */
+ int rc = misc_register(&g_MiscDevice);
+ if (!rc)
+ {
+ /*
+ * The device node intended to be accessible by all users.
+ */
+ rc = misc_register(&g_MiscDeviceUser);
+ if (!rc)
+ return 0;
+ LogRel((DEVICE_NAME ": misc_register failed for %s (rc=%d)\n", DEVICE_NAME_USER, rc));
+ misc_deregister(&g_MiscDevice);
+ }
+ else
+ LogRel((DEVICE_NAME ": misc_register failed for %s (rc=%d)\n", DEVICE_NAME, rc));
+ return rc;
+}
+
+
+/**
+ * Deregisters the device nodes.
+ */
+static void vgdrvLinuxTermDeviceNodes(void)
+{
+ misc_deregister(&g_MiscDevice);
+ misc_deregister(&g_MiscDeviceUser);
+}
+
+
+/**
+ * Initialize module.
+ *
+ * @returns appropriate status code.
+ */
+static int __init vgdrvLinuxModInit(void)
+{
+ static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
+ PRTLOGGER pRelLogger;
+ int rc;
+
+ /*
+ * Initialize IPRT first.
+ */
+ rc = RTR0Init(0);
+ if (RT_FAILURE(rc))
+ {
+ printk(KERN_ERR DEVICE_NAME ": RTR0Init failed, rc=%d.\n", rc);
+ return -EINVAL;
+ }
+
+ /*
+ * Create the release log.
+ * (We do that here instead of common code because we want to log
+ * early failures using the LogRel macro.)
+ */
+ rc = RTLogCreate(&pRelLogger, 0 /* fFlags */, "all",
+ "VBOX_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups,
+ RTLOGDEST_STDOUT | RTLOGDEST_DEBUGGER | RTLOGDEST_USER, NULL);
+ if (RT_SUCCESS(rc))
+ {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+ RTLogGroupSettings(pRelLogger, g_szLogGrp);
+ RTLogFlags(pRelLogger, g_szLogFlags);
+ RTLogDestinations(pRelLogger, g_szLogDst);
+#endif
+ RTLogRelSetDefaultInstance(pRelLogger);
+ }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+ g_fLoggerCreated = true;
+#endif
+
+ /*
+ * Locate and initialize the PCI device.
+ */
+ rc = pci_register_driver(&g_PciDriver);
+ if (rc >= 0 && g_pPciDev)
+ {
+ /*
+ * Register the interrupt service routine for it.
+ */
+ rc = vgdrvLinuxInitISR();
+ if (rc >= 0)
+ {
+ /*
+ * Call the common device extension initializer.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) && defined(RT_ARCH_X86)
+ VBOXOSTYPE enmOSType = VBOXOSTYPE_Linux26;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) && defined(RT_ARCH_AMD64)
+ VBOXOSTYPE enmOSType = VBOXOSTYPE_Linux26_x64;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) && defined(RT_ARCH_X86)
+ VBOXOSTYPE enmOSType = VBOXOSTYPE_Linux24;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) && defined(RT_ARCH_AMD64)
+ VBOXOSTYPE enmOSType = VBOXOSTYPE_Linux24_x64;
+#else
+# warning "huh? which arch + version is this?"
+ VBOXOSTYPE enmOsType = VBOXOSTYPE_Linux;
+#endif
+ rc = VGDrvCommonInitDevExt(&g_DevExt,
+ g_IOPortBase,
+ g_pvMMIOBase,
+ g_cbMMIO,
+ enmOSType,
+ VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Create the kernel session for this driver.
+ */
+ rc = VGDrvCommonCreateKernelSession(&g_DevExt, &g_pKernelSession);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Create the kernel input device.
+ */
+#ifdef VBOXGUEST_WITH_INPUT_DRIVER
+ rc = vgdrvLinuxCreateInputDevice();
+ if (rc >= 0)
+ {
+#endif
+ /*
+ * Finally, create the device nodes.
+ */
+ rc = vgdrvLinuxInitDeviceNodes();
+ if (rc >= 0)
+ {
+ /* some useful information for the user but don't show this on the console */
+ LogRel((DEVICE_NAME ": misc device minor %d, IRQ %d, I/O port %RTiop, MMIO at %RHp (size 0x%x)\n",
+ g_MiscDevice.minor, g_pPciDev->irq, g_IOPortBase, g_MMIOPhysAddr, g_cbMMIO));
+ printk(KERN_DEBUG DEVICE_NAME ": Successfully loaded version "
+ VBOX_VERSION_STRING " (interface " RT_XSTR(VMMDEV_VERSION) ")\n");
+ return rc;
+ }
+
+ /* bail out */
+#ifdef VBOXGUEST_WITH_INPUT_DRIVER
+ vgdrvLinuxTermInputDevice();
+ }
+ else
+ {
+ LogRel((DEVICE_NAME ": vboxguestCreateInputDevice failed with rc=%Rrc\n", rc));
+ rc = RTErrConvertFromErrno(rc);
+ }
+#endif
+ VGDrvCommonCloseSession(&g_DevExt, g_pKernelSession);
+ }
+ VGDrvCommonDeleteDevExt(&g_DevExt);
+ }
+ else
+ {
+ LogRel((DEVICE_NAME ": VGDrvCommonInitDevExt failed with rc=%Rrc\n", rc));
+ rc = RTErrConvertFromErrno(rc);
+ }
+ vgdrvLinuxTermISR();
+ }
+ }
+ else
+ {
+ LogRel((DEVICE_NAME ": PCI device not found, probably running on physical hardware.\n"));
+ rc = -ENODEV;
+ }
+ pci_unregister_driver(&g_PciDriver);
+ RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
+ RTLogDestroy(RTLogSetDefaultInstance(NULL));
+ RTR0Term();
+ return rc;
+}
+
+
+/**
+ * Unload the module.
+ */
+static void __exit vgdrvLinuxModExit(void)
+{
+ /*
+ * Inverse order of init.
+ */
+ vgdrvLinuxTermDeviceNodes();
+#ifdef VBOXGUEST_WITH_INPUT_DRIVER
+ vgdrvLinuxTermInputDevice();
+#endif
+ VGDrvCommonCloseSession(&g_DevExt, g_pKernelSession);
+ VGDrvCommonDeleteDevExt(&g_DevExt);
+ vgdrvLinuxTermISR();
+ pci_unregister_driver(&g_PciDriver);
+ RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
+ RTLogDestroy(RTLogSetDefaultInstance(NULL));
+ RTR0Term();
+}
+
+
+/**
+ * Device open. Called on open /dev/vboxdrv
+ *
+ * @param pInode Pointer to inode info structure.
+ * @param pFilp Associated file pointer.
+ */
+static int vgdrvLinuxOpen(struct inode *pInode, struct file *pFilp)
+{
+ int rc;
+ PVBOXGUESTSESSION pSession;
+ Log((DEVICE_NAME ": pFilp=%p pid=%d/%d %s\n", pFilp, RTProcSelf(), current->pid, current->comm));
+
+ /*
+ * Call common code to create the user session. Associate it with
+ * the file so we can access it in the other methods.
+ */
+ rc = VGDrvCommonCreateUserSession(&g_DevExt, &pSession);
+ if (RT_SUCCESS(rc))
+ {
+ pFilp->private_data = pSession;
+ if (MINOR(pInode->i_rdev) == g_MiscDeviceUser.minor)
+ pSession->fUserSession = true;
+ }
+
+ Log(("vgdrvLinuxOpen: g_DevExt=%p pSession=%p rc=%d/%d (pid=%d/%d %s)\n",
+ &g_DevExt, pSession, rc, vgdrvLinuxConvertToNegErrno(rc), RTProcSelf(), current->pid, current->comm));
+ return vgdrvLinuxConvertToNegErrno(rc);
+}
+
+
+/**
+ * Close device.
+ *
+ * @param pInode Pointer to inode info structure.
+ * @param pFilp Associated file pointer.
+ */
+static int vgdrvLinuxRelease(struct inode *pInode, struct file *pFilp)
+{
+ Log(("vgdrvLinuxRelease: pFilp=%p pSession=%p pid=%d/%d %s\n",
+ pFilp, pFilp->private_data, RTProcSelf(), current->pid, current->comm));
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28)
+ /* This housekeeping was needed in older kernel versions to ensure that
+ * the file pointer didn't get left on the polling queue. */
+ vgdrvLinuxFAsync(-1, pFilp, 0);
+#endif
+ VGDrvCommonCloseSession(&g_DevExt, (PVBOXGUESTSESSION)pFilp->private_data);
+ pFilp->private_data = NULL;
+ return 0;
+}
+
+
+/**
+ * Device I/O Control entry point.
+ *
+ * @param pInode Associated inode pointer.
+ * @param pFilp Associated file pointer.
+ * @param uCmd The function specified to ioctl().
+ * @param ulArg The argument specified to ioctl().
+ */
+#ifdef HAVE_UNLOCKED_IOCTL
+static long vgdrvLinuxIOCtl(struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
+#else
+static int vgdrvLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
+#endif
+{
+ PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pFilp->private_data;
+ uint32_t cbData = _IOC_SIZE(uCmd);
+ void *pvBufFree;
+ void *pvBuf;
+ int rc;
+ uint64_t au64Buf[32/sizeof(uint64_t)];
+
+ Log6(("vgdrvLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p pid=%d/%d\n", pFilp, uCmd, (void *)ulArg, RTProcSelf(), current->pid));
+
+ /*
+ * Buffer the request.
+ */
+ if (cbData <= sizeof(au64Buf))
+ {
+ pvBufFree = NULL;
+ pvBuf = &au64Buf[0];
+ }
+ else
+ {
+ pvBufFree = pvBuf = RTMemTmpAlloc(cbData);
+ if (RT_UNLIKELY(!pvBuf))
+ {
+ LogRel((DEVICE_NAME "::IOCtl: RTMemTmpAlloc failed to alloc %u bytes.\n", cbData));
+ return -ENOMEM;
+ }
+ }
+ if (RT_LIKELY(copy_from_user(pvBuf, (void *)ulArg, cbData) == 0))
+ {
+ /*
+ * Process the IOCtl.
+ */
+ size_t cbDataReturned;
+ rc = VGDrvCommonIoCtl(uCmd, &g_DevExt, pSession, pvBuf, cbData, &cbDataReturned);
+
+ /*
+ * Copy ioctl data and output buffer back to user space.
+ */
+ if (RT_SUCCESS(rc))
+ {
+ rc = 0;
+ if (RT_UNLIKELY(cbDataReturned > cbData))
+ {
+ LogRel((DEVICE_NAME "::IOCtl: too much output data %u expected %u\n", cbDataReturned, cbData));
+ cbDataReturned = cbData;
+ }
+ if (cbDataReturned > 0)
+ {
+ if (RT_UNLIKELY(copy_to_user((void *)ulArg, pvBuf, cbDataReturned) != 0))
+ {
+ LogRel((DEVICE_NAME "::IOCtl: copy_to_user failed; pvBuf=%p ulArg=%p cbDataReturned=%u uCmd=%d\n",
+ pvBuf, (void *)ulArg, cbDataReturned, uCmd, rc));
+ rc = -EFAULT;
+ }
+ }
+ }
+ else
+ {
+ Log(("vgdrvLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p failed, rc=%d\n", pFilp, uCmd, (void *)ulArg, rc));
+ rc = -rc; Assert(rc > 0); /* Positive returns == negated VBox error status codes. */
+ }
+ }
+ else
+ {
+ Log((DEVICE_NAME "::IOCtl: copy_from_user(,%#lx, %#x) failed; uCmd=%#x.\n", ulArg, cbData, uCmd));
+ rc = -EFAULT;
+ }
+ if (pvBufFree)
+ RTMemFree(pvBufFree);
+
+ Log6(("vgdrvLinuxIOCtl: returns %d (pid=%d/%d)\n", rc, RTProcSelf(), current->pid));
+ return rc;
+}
+
+
+/**
+ * Asynchronous notification activation method.
+ *
+ * @returns 0 on success, negative errno on failure.
+ *
+ * @param fd The file descriptor.
+ * @param pFile The file structure.
+ * @param fOn On/off indicator.
+ */
+static int vgdrvLinuxFAsync(int fd, struct file *pFile, int fOn)
+{
+ return fasync_helper(fd, pFile, fOn, &g_pFAsyncQueue);
+}
+
+
+/**
+ * Poll function.
+ *
+ * This returns ready to read if the mouse pointer mode or the pointer position
+ * has changed since last call to read.
+ *
+ * @returns 0 if no changes, POLLIN | POLLRDNORM if there are unseen changes.
+ *
+ * @param pFile The file structure.
+ * @param pPt The poll table.
+ *
+ * @remarks This is probably not really used, X11 is said to use the fasync
+ * interface instead.
+ */
+static unsigned int vgdrvLinuxPoll(struct file *pFile, poll_table *pPt)
+{
+ PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pFile->private_data;
+ uint32_t u32CurSeq = ASMAtomicUoReadU32(&g_DevExt.u32MousePosChangedSeq);
+ unsigned int fMask = pSession->u32MousePosChangedSeq != u32CurSeq
+ ? POLLIN | POLLRDNORM
+ : 0;
+ poll_wait(pFile, &g_PollEventQueue, pPt);
+ return fMask;
+}
+
+
+/**
+ * Read to go with our poll/fasync response.
+ *
+ * @returns 1 or -EINVAL.
+ *
+ * @param pFile The file structure.
+ * @param pbBuf The buffer to read into.
+ * @param cbRead The max number of bytes to read.
+ * @param poff The current file position.
+ *
+ * @remarks This is probably not really used as X11 lets the driver do its own
+ * event reading. The poll condition is therefore also cleared when we
+ * see VMMDevReq_GetMouseStatus in vgdrvIoCtl_VMMRequest.
+ */
+static ssize_t vgdrvLinuxRead(struct file *pFile, char *pbBuf, size_t cbRead, loff_t *poff)
+{
+ PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pFile->private_data;
+ uint32_t u32CurSeq = ASMAtomicUoReadU32(&g_DevExt.u32MousePosChangedSeq);
+
+ if (*poff != 0)
+ return -EINVAL;
+
+ /*
+ * Fake a single byte read if we're not up to date with the current mouse position.
+ */
+ if ( pSession->u32MousePosChangedSeq != u32CurSeq
+ && cbRead > 0)
+ {
+ pSession->u32MousePosChangedSeq = u32CurSeq;
+ pbBuf[0] = 0;
+ return 1;
+ }
+ return 0;
+}
+
+
+void VGDrvNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt)
+{
+#ifdef VBOXGUEST_WITH_INPUT_DRIVER
+ int rc;
+#endif
+ NOREF(pDevExt);
+
+ /*
+ * Wake up everyone that's in a poll() and post anyone that has
+ * subscribed to async notifications.
+ */
+ Log3(("VGDrvNativeISRMousePollEvent: wake_up_all\n"));
+ wake_up_all(&g_PollEventQueue);
+ Log3(("VGDrvNativeISRMousePollEvent: kill_fasync\n"));
+ kill_fasync(&g_pFAsyncQueue, SIGIO, POLL_IN);
+#ifdef VBOXGUEST_WITH_INPUT_DRIVER
+ /* Report events to the kernel input device */
+ g_pMouseStatusReq->mouseFeatures = 0;
+ g_pMouseStatusReq->pointerXPos = 0;
+ g_pMouseStatusReq->pointerYPos = 0;
+ rc = VbglGRPerform(&g_pMouseStatusReq->header);
+ if (RT_SUCCESS(rc))
+ {
+ input_report_abs(g_pInputDevice, ABS_X,
+ g_pMouseStatusReq->pointerXPos);
+ input_report_abs(g_pInputDevice, ABS_Y,
+ g_pMouseStatusReq->pointerYPos);
+# ifdef EV_SYN
+ input_sync(g_pInputDevice);
+# endif
+ }
+#endif
+ Log3(("VGDrvNativeISRMousePollEvent: done\n"));
+}
+
+
+/* Common code that depend on g_DevExt. */
+#include "VBoxGuestIDC-unix.c.h"
+
+EXPORT_SYMBOL(VBoxGuestIDCOpen);
+EXPORT_SYMBOL(VBoxGuestIDCClose);
+EXPORT_SYMBOL(VBoxGuestIDCCall);
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+
+/** log and dbg_log parameter setter. */
+static int vgdrvLinuxParamLogGrpSet(const char *pszValue, struct kernel_param *pParam)
+{
+ if (g_fLoggerCreated)
+ {
+ PRTLOGGER pLogger = pParam->name[0] == 'd' ? RTLogDefaultInstance() : RTLogRelGetDefaultInstance();
+ if (pLogger)
+ RTLogGroupSettings(pLogger, pszValue);
+ }
+ else if (pParam->name[0] != 'd')
+ strlcpy(&g_szLogGrp[0], pszValue, sizeof(g_szLogGrp));
+
+ return 0;
+}
+
+/** log and dbg_log parameter getter. */
+static int vgdrvLinuxParamLogGrpGet(char *pszBuf, struct kernel_param *pParam)
+{
+ PRTLOGGER pLogger = pParam->name[0] == 'd' ? RTLogDefaultInstance() : RTLogRelGetDefaultInstance();
+ *pszBuf = '\0';
+ if (pLogger)
+ RTLogGetGroupSettings(pLogger, pszBuf, _4K);
+ return strlen(pszBuf);
+}
+
+
+/** log and dbg_log_flags parameter setter. */
+static int vgdrvLinuxParamLogFlagsSet(const char *pszValue, struct kernel_param *pParam)
+{
+ if (g_fLoggerCreated)
+ {
+ PRTLOGGER pLogger = pParam->name[0] == 'd' ? RTLogDefaultInstance() : RTLogRelGetDefaultInstance();
+ if (pLogger)
+ RTLogFlags(pLogger, pszValue);
+ }
+ else if (pParam->name[0] != 'd')
+ strlcpy(&g_szLogFlags[0], pszValue, sizeof(g_szLogFlags));
+ return 0;
+}
+
+/** log and dbg_log_flags parameter getter. */
+static int vgdrvLinuxParamLogFlagsGet(char *pszBuf, struct kernel_param *pParam)
+{
+ PRTLOGGER pLogger = pParam->name[0] == 'd' ? RTLogDefaultInstance() : RTLogRelGetDefaultInstance();
+ *pszBuf = '\0';
+ if (pLogger)
+ RTLogGetFlags(pLogger, pszBuf, _4K);
+ return strlen(pszBuf);
+}
+
+
+/** log and dbg_log_dest parameter setter. */
+static int vgdrvLinuxParamLogDstSet(const char *pszValue, struct kernel_param *pParam)
+{
+ if (g_fLoggerCreated)
+ {
+ PRTLOGGER pLogger = pParam->name[0] == 'd' ? RTLogDefaultInstance() : RTLogRelGetDefaultInstance();
+ if (pLogger)
+ RTLogDestinations(pLogger, pszValue);
+ }
+ else if (pParam->name[0] != 'd')
+ strlcpy(&g_szLogDst[0], pszValue, sizeof(g_szLogDst));
+ return 0;
+}
+
+/** log and dbg_log_dest parameter getter. */
+static int vgdrvLinuxParamLogDstGet(char *pszBuf, struct kernel_param *pParam)
+{
+ PRTLOGGER pLogger = pParam->name[0] == 'd' ? RTLogDefaultInstance() : RTLogRelGetDefaultInstance();
+ *pszBuf = '\0';
+ if (pLogger)
+ RTLogGetDestinations(pLogger, pszBuf, _4K);
+ return strlen(pszBuf);
+}
+
+
+/** r3_log_to_host parameter setter. */
+static int vgdrvLinuxParamR3LogToHostSet(const char *pszValue, struct kernel_param *pParam)
+{
+ if ( pszValue == NULL
+ || *pszValue == '\0'
+ || *pszValue == 'n'
+ || *pszValue == 'N'
+ || *pszValue == 'd'
+ || *pszValue == 'D'
+ || ( (*pszValue == 'o' || *pszValue == 'O')
+ && (*pszValue == 'f' || *pszValue == 'F') )
+ )
+ g_DevExt.fLoggingEnabled = false;
+ else
+ g_DevExt.fLoggingEnabled = true;
+ return 0;
+}
+
+/** r3_log_to_host parameter getter. */
+static int vgdrvLinuxParamR3LogToHostGet(char *pszBuf, struct kernel_param *pParam)
+{
+ strcpy(pszBuf, g_DevExt.fLoggingEnabled ? "enabled" : "disabled");
+ return strlen(pszBuf);
+}
+
+
+/*
+ * Define module parameters.
+ */
+module_param_call(log, vgdrvLinuxParamLogGrpSet, vgdrvLinuxParamLogGrpGet, NULL, 0664);
+module_param_call(log_flags, vgdrvLinuxParamLogFlagsSet, vgdrvLinuxParamLogFlagsGet, NULL, 0664);
+module_param_call(log_dest, vgdrvLinuxParamLogDstSet, vgdrvLinuxParamLogDstGet, NULL, 0664);
+# ifdef LOG_ENABLED
+module_param_call(dbg_log, vgdrvLinuxParamLogGrpSet, vgdrvLinuxParamLogGrpGet, NULL, 0664);
+module_param_call(dbg_log_flags, vgdrvLinuxParamLogFlagsSet, vgdrvLinuxParamLogFlagsGet, NULL, 0664);
+module_param_call(dbg_log_dest, vgdrvLinuxParamLogDstSet, vgdrvLinuxParamLogDstGet, NULL, 0664);
+# endif
+module_param_call(r3_log_to_host, vgdrvLinuxParamR3LogToHostSet, vgdrvLinuxParamR3LogToHostGet, NULL, 0664);
+
+#endif /* 2.6.0 and later */
+
+
+module_init(vgdrvLinuxModInit);
+module_exit(vgdrvLinuxModExit);
+
+MODULE_AUTHOR(VBOX_VENDOR);
+MODULE_DESCRIPTION(VBOX_PRODUCT " Guest Additions for Linux Module");
+MODULE_LICENSE("GPL");
+#ifdef MODULE_VERSION
+MODULE_VERSION(VBOX_VERSION_STRING " r" RT_XSTR(VBOX_SVN_REV));
+#endif
+
--- /dev/null
+/* $Id: VBoxGuest.cpp $ */
+/** @file
+ * VBoxGuest - Guest Additions Driver, Common Code.
+ */
+
+/*
+ * Copyright (C) 2007-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+/** @page pg_vbdrv VBoxGuest
+ *
+ * VBoxGuest is the device driver for VMMDev.
+ *
+ * The device driver is shipped as part of the guest additions. It has roots in
+ * the host VMM support driver (usually known as VBoxDrv), so fixes in platform
+ * specific code may apply to both drivers.
+ *
+ * The common code lives in VBoxGuest.cpp and is compiled both as C++ and C.
+ * The VBoxGuest.cpp source file shall not contain platform specific code,
+ * though it must occationally do a few \#ifdef RT_OS_XXX tests to cater for
+ * platform differences. Though, in those cases, it is common that more than
+ * one platform needs special handling.
+ *
+ * On most platforms the device driver should create two device nodes, one for
+ * full (unrestricted) access to the feature set, and one which only provides a
+ * restrict set of functions. These are generally referred to as 'vboxguest'
+ * and 'vboxuser' respectively. Currently, this two device approach is only
+ * implemented on Linux!
+ *
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_DEFAULT
+#include "VBoxGuestInternal.h"
+#include <VBox/VMMDev.h> /* for VMMDEV_RAM_SIZE */
+#include <VBox/log.h>
+#include <iprt/mem.h>
+#include <iprt/time.h>
+#include <iprt/memobj.h>
+#include <iprt/asm.h>
+#include <iprt/asm-amd64-x86.h>
+#include <iprt/string.h>
+#include <iprt/process.h>
+#include <iprt/assert.h>
+#include <iprt/param.h>
+#include <iprt/timer.h>
+#ifdef VBOX_WITH_HGCM
+# include <iprt/thread.h>
+#endif
+#include "version-generated.h"
+#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
+# include "revision-generated.h"
+#endif
+#ifdef RT_OS_WINDOWS
+# ifndef CTL_CODE
+# include <iprt/win/windows.h>
+# endif
+#endif
+#if defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN)
+# include <iprt/rand.h>
+#endif
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+#define VBOXGUEST_ACQUIRE_STYLE_EVENTS (VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST | VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST)
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+#ifdef VBOX_WITH_HGCM
+static DECLCALLBACK(int) vgdrvHgcmAsyncWaitCallback(VMMDevHGCMRequestHeader *pHdrNonVolatile, void *pvUser, uint32_t u32User);
+#endif
+static int vgdrvIoCtl_CancelAllWaitEvents(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession);
+static void vgdrvBitUsageTrackerClear(PVBOXGUESTBITUSAGETRACER pTracker);
+static uint32_t vgdrvGetAllowedEventMaskForSession(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession);
+static int vgdrvResetEventFilterOnHost(PVBOXGUESTDEVEXT pDevExt, uint32_t fFixedEvents);
+static int vgdrvResetMouseStatusOnHost(PVBOXGUESTDEVEXT pDevExt);
+static int vgdrvResetCapabilitiesOnHost(PVBOXGUESTDEVEXT pDevExt);
+static int vgdrvSetSessionEventFilter(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
+ uint32_t fOrMask, uint32_t fNotMask, bool fSessionTermination);
+static int vgdrvSetSessionMouseStatus(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
+ uint32_t fOrMask, uint32_t fNotMask, bool fSessionTermination);
+static int vgdrvSetSessionCapabilities(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
+ uint32_t fOrMask, uint32_t fNoMask, bool fSessionTermination);
+static int vgdrvAcquireSessionCapabilities(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fOrMask,
+ uint32_t fNotMask, VBOXGUESTCAPSACQUIRE_FLAGS enmFlags, bool fSessionTermination);
+static int vgdrvDispatchEventsLocked(PVBOXGUESTDEVEXT pDevExt, uint32_t fEvents);
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+static const uint32_t g_cbChangeMemBalloonReq = RT_OFFSETOF(VMMDevChangeMemBalloon, aPhysPage[VMMDEV_MEMORY_BALLOON_CHUNK_PAGES]);
+
+#if defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS)
+/**
+ * Drag in the rest of IRPT since we share it with the
+ * rest of the kernel modules on Solaris.
+ */
+PFNRT g_apfnVBoxGuestIPRTDeps[] =
+{
+ /* VirtioNet */
+ (PFNRT)RTRandBytes,
+ /* RTSemMutex* */
+ (PFNRT)RTSemMutexCreate,
+ (PFNRT)RTSemMutexDestroy,
+ (PFNRT)RTSemMutexRequest,
+ (PFNRT)RTSemMutexRequestNoResume,
+ (PFNRT)RTSemMutexRequestDebug,
+ (PFNRT)RTSemMutexRequestNoResumeDebug,
+ (PFNRT)RTSemMutexRelease,
+ (PFNRT)RTSemMutexIsOwned,
+ NULL
+};
+#endif /* RT_OS_DARWIN || RT_OS_SOLARIS */
+
+
+/**
+ * Reserves memory in which the VMM can relocate any guest mappings
+ * that are floating around.
+ *
+ * This operation is a little bit tricky since the VMM might not accept
+ * just any address because of address clashes between the three contexts
+ * it operates in, so use a small stack to perform this operation.
+ *
+ * @returns VBox status code (ignored).
+ * @param pDevExt The device extension.
+ */
+static int vgdrvInitFixateGuestMappings(PVBOXGUESTDEVEXT pDevExt)
+{
+ /*
+ * Query the required space.
+ */
+ VMMDevReqHypervisorInfo *pReq;
+ int rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(VMMDevReqHypervisorInfo), VMMDevReq_GetHypervisorInfo);
+ if (RT_FAILURE(rc))
+ return rc;
+ pReq->hypervisorStart = 0;
+ pReq->hypervisorSize = 0;
+ rc = VbglGRPerform(&pReq->header);
+ if (RT_FAILURE(rc)) /* this shouldn't happen! */
+ {
+ VbglGRFree(&pReq->header);
+ return rc;
+ }
+
+ /*
+ * The VMM will report back if there is nothing it wants to map, like for
+ * instance in VT-x and AMD-V mode.
+ */
+ if (pReq->hypervisorSize == 0)
+ Log(("vgdrvInitFixateGuestMappings: nothing to do\n"));
+ else
+ {
+ /*
+ * We have to try several times since the host can be picky
+ * about certain addresses.
+ */
+ RTR0MEMOBJ hFictive = NIL_RTR0MEMOBJ;
+ uint32_t cbHypervisor = pReq->hypervisorSize;
+ RTR0MEMOBJ ahTries[5];
+ uint32_t iTry;
+ bool fBitched = false;
+ Log(("vgdrvInitFixateGuestMappings: cbHypervisor=%#x\n", cbHypervisor));
+ for (iTry = 0; iTry < RT_ELEMENTS(ahTries); iTry++)
+ {
+ /*
+ * Reserve space, or if that isn't supported, create a object for
+ * some fictive physical memory and map that in to kernel space.
+ *
+ * To make the code a bit uglier, most systems cannot help with
+ * 4MB alignment, so we have to deal with that in addition to
+ * having two ways of getting the memory.
+ */
+ uint32_t uAlignment = _4M;
+ RTR0MEMOBJ hObj;
+ rc = RTR0MemObjReserveKernel(&hObj, (void *)-1, RT_ALIGN_32(cbHypervisor, _4M), uAlignment);
+ if (rc == VERR_NOT_SUPPORTED)
+ {
+ uAlignment = PAGE_SIZE;
+ rc = RTR0MemObjReserveKernel(&hObj, (void *)-1, RT_ALIGN_32(cbHypervisor, _4M) + _4M, uAlignment);
+ }
+ /*
+ * If both RTR0MemObjReserveKernel calls above failed because either not supported or
+ * not implemented at all at the current platform, try to map the memory object into the
+ * virtual kernel space.
+ */
+ if (rc == VERR_NOT_SUPPORTED)
+ {
+ if (hFictive == NIL_RTR0MEMOBJ)
+ {
+ rc = RTR0MemObjEnterPhys(&hObj, VBOXGUEST_HYPERVISOR_PHYSICAL_START, cbHypervisor + _4M, RTMEM_CACHE_POLICY_DONT_CARE);
+ if (RT_FAILURE(rc))
+ break;
+ hFictive = hObj;
+ }
+ uAlignment = _4M;
+ rc = RTR0MemObjMapKernel(&hObj, hFictive, (void *)-1, uAlignment, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
+ if (rc == VERR_NOT_SUPPORTED)
+ {
+ uAlignment = PAGE_SIZE;
+ rc = RTR0MemObjMapKernel(&hObj, hFictive, (void *)-1, uAlignment, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
+ }
+ }
+ if (RT_FAILURE(rc))
+ {
+ LogRel(("VBoxGuest: Failed to reserve memory for the hypervisor: rc=%Rrc (cbHypervisor=%#x uAlignment=%#x iTry=%u)\n",
+ rc, cbHypervisor, uAlignment, iTry));
+ fBitched = true;
+ break;
+ }
+
+ /*
+ * Try set it.
+ */
+ pReq->header.requestType = VMMDevReq_SetHypervisorInfo;
+ pReq->header.rc = VERR_INTERNAL_ERROR;
+ pReq->hypervisorSize = cbHypervisor;
+ pReq->hypervisorStart = (RTGCPTR32)(uintptr_t)RTR0MemObjAddress(hObj);
+ if ( uAlignment == PAGE_SIZE
+ && pReq->hypervisorStart & (_4M - 1))
+ pReq->hypervisorStart = RT_ALIGN_32(pReq->hypervisorStart, _4M);
+ AssertMsg(RT_ALIGN_32(pReq->hypervisorStart, _4M) == pReq->hypervisorStart, ("%#x\n", pReq->hypervisorStart));
+
+ rc = VbglGRPerform(&pReq->header);
+ if (RT_SUCCESS(rc))
+ {
+ pDevExt->hGuestMappings = hFictive != NIL_RTR0MEMOBJ ? hFictive : hObj;
+ Log(("VBoxGuest: %p LB %#x; uAlignment=%#x iTry=%u hGuestMappings=%p (%s)\n",
+ RTR0MemObjAddress(pDevExt->hGuestMappings),
+ RTR0MemObjSize(pDevExt->hGuestMappings),
+ uAlignment, iTry, pDevExt->hGuestMappings, hFictive != NIL_RTR0PTR ? "fictive" : "reservation"));
+ break;
+ }
+ ahTries[iTry] = hObj;
+ }
+
+ /*
+ * Cleanup failed attempts.
+ */
+ while (iTry-- > 0)
+ RTR0MemObjFree(ahTries[iTry], false /* fFreeMappings */);
+ if ( RT_FAILURE(rc)
+ && hFictive != NIL_RTR0PTR)
+ RTR0MemObjFree(hFictive, false /* fFreeMappings */);
+ if (RT_FAILURE(rc) && !fBitched)
+ LogRel(("VBoxGuest: Warning: failed to reserve %#d of memory for guest mappings.\n", cbHypervisor));
+ }
+ VbglGRFree(&pReq->header);
+
+ /*
+ * We ignore failed attempts for now.
+ */
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Undo what vgdrvInitFixateGuestMappings did.
+ *
+ * @param pDevExt The device extension.
+ */
+static void vgdrvTermUnfixGuestMappings(PVBOXGUESTDEVEXT pDevExt)
+{
+ if (pDevExt->hGuestMappings != NIL_RTR0PTR)
+ {
+ /*
+ * Tell the host that we're going to free the memory we reserved for
+ * it, the free it up. (Leak the memory if anything goes wrong here.)
+ */
+ VMMDevReqHypervisorInfo *pReq;
+ int rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(VMMDevReqHypervisorInfo), VMMDevReq_SetHypervisorInfo);
+ if (RT_SUCCESS(rc))
+ {
+ pReq->hypervisorStart = 0;
+ pReq->hypervisorSize = 0;
+ rc = VbglGRPerform(&pReq->header);
+ VbglGRFree(&pReq->header);
+ }
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTR0MemObjFree(pDevExt->hGuestMappings, true /* fFreeMappings */);
+ AssertRC(rc);
+ }
+ else
+ LogRel(("vgdrvTermUnfixGuestMappings: Failed to unfix the guest mappings! rc=%Rrc\n", rc));
+
+ pDevExt->hGuestMappings = NIL_RTR0MEMOBJ;
+ }
+}
+
+
+
+/**
+ * Report the guest information to the host.
+ *
+ * @returns IPRT status code.
+ * @param enmOSType The OS type to report.
+ */
+static int vgdrvReportGuestInfo(VBOXOSTYPE enmOSType)
+{
+ /*
+ * Allocate and fill in the two guest info reports.
+ */
+ VMMDevReportGuestInfo2 *pReqInfo2 = NULL;
+ VMMDevReportGuestInfo *pReqInfo1 = NULL;
+ int rc = VbglGRAlloc((VMMDevRequestHeader **)&pReqInfo2, sizeof (VMMDevReportGuestInfo2), VMMDevReq_ReportGuestInfo2);
+ Log(("vgdrvReportGuestInfo: VbglGRAlloc VMMDevReportGuestInfo2 completed with rc=%Rrc\n", rc));
+ if (RT_SUCCESS(rc))
+ {
+ pReqInfo2->guestInfo.additionsMajor = VBOX_VERSION_MAJOR;
+ pReqInfo2->guestInfo.additionsMinor = VBOX_VERSION_MINOR;
+ pReqInfo2->guestInfo.additionsBuild = VBOX_VERSION_BUILD;
+ pReqInfo2->guestInfo.additionsRevision = VBOX_SVN_REV;
+ pReqInfo2->guestInfo.additionsFeatures = 0; /* (no features defined yet) */
+ RTStrCopy(pReqInfo2->guestInfo.szName, sizeof(pReqInfo2->guestInfo.szName), VBOX_VERSION_STRING);
+
+ rc = VbglGRAlloc((VMMDevRequestHeader **)&pReqInfo1, sizeof (VMMDevReportGuestInfo), VMMDevReq_ReportGuestInfo);
+ Log(("vgdrvReportGuestInfo: VbglGRAlloc VMMDevReportGuestInfo completed with rc=%Rrc\n", rc));
+ if (RT_SUCCESS(rc))
+ {
+ pReqInfo1->guestInfo.interfaceVersion = VMMDEV_VERSION;
+ pReqInfo1->guestInfo.osType = enmOSType;
+
+ /*
+ * There are two protocols here:
+ * 1. Info2 + Info1. Supported by >=3.2.51.
+ * 2. Info1 and optionally Info2. The old protocol.
+ *
+ * We try protocol 1 first. It will fail with VERR_NOT_SUPPORTED
+ * if not supported by the VMMDev (message ordering requirement).
+ */
+ rc = VbglGRPerform(&pReqInfo2->header);
+ Log(("vgdrvReportGuestInfo: VbglGRPerform VMMDevReportGuestInfo2 completed with rc=%Rrc\n", rc));
+ if (RT_SUCCESS(rc))
+ {
+ rc = VbglGRPerform(&pReqInfo1->header);
+ Log(("vgdrvReportGuestInfo: VbglGRPerform VMMDevReportGuestInfo completed with rc=%Rrc\n", rc));
+ }
+ else if ( rc == VERR_NOT_SUPPORTED
+ || rc == VERR_NOT_IMPLEMENTED)
+ {
+ rc = VbglGRPerform(&pReqInfo1->header);
+ Log(("vgdrvReportGuestInfo: VbglGRPerform VMMDevReportGuestInfo completed with rc=%Rrc\n", rc));
+ if (RT_SUCCESS(rc))
+ {
+ rc = VbglGRPerform(&pReqInfo2->header);
+ Log(("vgdrvReportGuestInfo: VbglGRPerform VMMDevReportGuestInfo2 completed with rc=%Rrc\n", rc));
+ if (rc == VERR_NOT_IMPLEMENTED)
+ rc = VINF_SUCCESS;
+ }
+ }
+ VbglGRFree(&pReqInfo1->header);
+ }
+ VbglGRFree(&pReqInfo2->header);
+ }
+
+ return rc;
+}
+
+
+/**
+ * Report the guest driver status to the host.
+ *
+ * @returns IPRT status code.
+ * @param fActive Flag whether the driver is now active or not.
+ */
+static int vgdrvReportDriverStatus(bool fActive)
+{
+ /*
+ * Report guest status of the VBox driver to the host.
+ */
+ VMMDevReportGuestStatus *pReq2 = NULL;
+ int rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq2, sizeof(*pReq2), VMMDevReq_ReportGuestStatus);
+ Log(("vgdrvReportDriverStatus: VbglGRAlloc VMMDevReportGuestStatus completed with rc=%Rrc\n", rc));
+ if (RT_SUCCESS(rc))
+ {
+ pReq2->guestStatus.facility = VBoxGuestFacilityType_VBoxGuestDriver;
+ pReq2->guestStatus.status = fActive ?
+ VBoxGuestFacilityStatus_Active
+ : VBoxGuestFacilityStatus_Inactive;
+ pReq2->guestStatus.flags = 0;
+ rc = VbglGRPerform(&pReq2->header);
+ Log(("vgdrvReportDriverStatus: VbglGRPerform VMMDevReportGuestStatus completed with fActive=%d, rc=%Rrc\n",
+ fActive ? 1 : 0, rc));
+ if (rc == VERR_NOT_IMPLEMENTED) /* Compatibility with older hosts. */
+ rc = VINF_SUCCESS;
+ VbglGRFree(&pReq2->header);
+ }
+
+ return rc;
+}
+
+
+/** @name Memory Ballooning
+ * @{
+ */
+
+/**
+ * Inflate the balloon by one chunk represented by an R0 memory object.
+ *
+ * The caller owns the balloon mutex.
+ *
+ * @returns IPRT status code.
+ * @param pMemObj Pointer to the R0 memory object.
+ * @param pReq The pre-allocated request for performing the VMMDev call.
+ */
+static int vgdrvBalloonInflate(PRTR0MEMOBJ pMemObj, VMMDevChangeMemBalloon *pReq)
+{
+ uint32_t iPage;
+ int rc;
+
+ for (iPage = 0; iPage < VMMDEV_MEMORY_BALLOON_CHUNK_PAGES; iPage++)
+ {
+ RTHCPHYS phys = RTR0MemObjGetPagePhysAddr(*pMemObj, iPage);
+ pReq->aPhysPage[iPage] = phys;
+ }
+
+ pReq->fInflate = true;
+ pReq->header.size = g_cbChangeMemBalloonReq;
+ pReq->cPages = VMMDEV_MEMORY_BALLOON_CHUNK_PAGES;
+
+ rc = VbglGRPerform(&pReq->header);
+ if (RT_FAILURE(rc))
+ LogRel(("vgdrvBalloonInflate: VbglGRPerform failed. rc=%Rrc\n", rc));
+ return rc;
+}
+
+
+/**
+ * Deflate the balloon by one chunk - info the host and free the memory object.
+ *
+ * The caller owns the balloon mutex.
+ *
+ * @returns IPRT status code.
+ * @param pMemObj Pointer to the R0 memory object.
+ * The memory object will be freed afterwards.
+ * @param pReq The pre-allocated request for performing the VMMDev call.
+ */
+static int vgdrvBalloonDeflate(PRTR0MEMOBJ pMemObj, VMMDevChangeMemBalloon *pReq)
+{
+ uint32_t iPage;
+ int rc;
+
+ for (iPage = 0; iPage < VMMDEV_MEMORY_BALLOON_CHUNK_PAGES; iPage++)
+ {
+ RTHCPHYS phys = RTR0MemObjGetPagePhysAddr(*pMemObj, iPage);
+ pReq->aPhysPage[iPage] = phys;
+ }
+
+ pReq->fInflate = false;
+ pReq->header.size = g_cbChangeMemBalloonReq;
+ pReq->cPages = VMMDEV_MEMORY_BALLOON_CHUNK_PAGES;
+
+ rc = VbglGRPerform(&pReq->header);
+ if (RT_FAILURE(rc))
+ {
+ LogRel(("vgdrvBalloonDeflate: VbglGRPerform failed. rc=%Rrc\n", rc));
+ return rc;
+ }
+
+ rc = RTR0MemObjFree(*pMemObj, true);
+ if (RT_FAILURE(rc))
+ {
+ LogRel(("vgdrvBalloonDeflate: RTR0MemObjFree(%p,true) -> %Rrc; this is *BAD*!\n", *pMemObj, rc));
+ return rc;
+ }
+
+ *pMemObj = NIL_RTR0MEMOBJ;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Inflate/deflate the memory balloon and notify the host.
+ *
+ * This is a worker used by vgdrvIoCtl_CheckMemoryBalloon - it takes the mutex.
+ *
+ * @returns VBox status code.
+ * @param pDevExt The device extension.
+ * @param cBalloonChunks The new size of the balloon in chunks of 1MB.
+ * @param pfHandleInR3 Where to return the handle-in-ring3 indicator
+ * (VINF_SUCCESS if set).
+ */
+static int vgdrvSetBalloonSizeKernel(PVBOXGUESTDEVEXT pDevExt, uint32_t cBalloonChunks, uint32_t *pfHandleInR3)
+{
+ int rc = VINF_SUCCESS;
+
+ if (pDevExt->MemBalloon.fUseKernelAPI)
+ {
+ VMMDevChangeMemBalloon *pReq;
+ uint32_t i;
+
+ if (cBalloonChunks > pDevExt->MemBalloon.cMaxChunks)
+ {
+ LogRel(("vgdrvSetBalloonSizeKernel: illegal balloon size %u (max=%u)\n",
+ cBalloonChunks, pDevExt->MemBalloon.cMaxChunks));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ if (cBalloonChunks == pDevExt->MemBalloon.cMaxChunks)
+ return VINF_SUCCESS; /* nothing to do */
+
+ if ( cBalloonChunks > pDevExt->MemBalloon.cChunks
+ && !pDevExt->MemBalloon.paMemObj)
+ {
+ pDevExt->MemBalloon.paMemObj = (PRTR0MEMOBJ)RTMemAllocZ(sizeof(RTR0MEMOBJ) * pDevExt->MemBalloon.cMaxChunks);
+ if (!pDevExt->MemBalloon.paMemObj)
+ {
+ LogRel(("vgdrvSetBalloonSizeKernel: no memory for paMemObj!\n"));
+ return VERR_NO_MEMORY;
+ }
+ }
+
+ rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, g_cbChangeMemBalloonReq, VMMDevReq_ChangeMemBalloon);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ if (cBalloonChunks > pDevExt->MemBalloon.cChunks)
+ {
+ /* inflate */
+ for (i = pDevExt->MemBalloon.cChunks; i < cBalloonChunks; i++)
+ {
+ rc = RTR0MemObjAllocPhysNC(&pDevExt->MemBalloon.paMemObj[i],
+ VMMDEV_MEMORY_BALLOON_CHUNK_SIZE, NIL_RTHCPHYS);
+ if (RT_FAILURE(rc))
+ {
+ if (rc == VERR_NOT_SUPPORTED)
+ {
+ /* not supported -- fall back to the R3-allocated memory. */
+ rc = VINF_SUCCESS;
+ pDevExt->MemBalloon.fUseKernelAPI = false;
+ Assert(pDevExt->MemBalloon.cChunks == 0);
+ Log(("VBoxGuestSetBalloonSizeKernel: PhysNC allocs not supported, falling back to R3 allocs.\n"));
+ }
+ /* else if (rc == VERR_NO_MEMORY || rc == VERR_NO_PHYS_MEMORY):
+ * cannot allocate more memory => don't try further, just stop here */
+ /* else: XXX what else can fail? VERR_MEMOBJ_INIT_FAILED for instance. just stop. */
+ break;
+ }
+
+ rc = vgdrvBalloonInflate(&pDevExt->MemBalloon.paMemObj[i], pReq);
+ if (RT_FAILURE(rc))
+ {
+ Log(("vboxGuestSetBalloonSize(inflate): failed, rc=%Rrc!\n", rc));
+ RTR0MemObjFree(pDevExt->MemBalloon.paMemObj[i], true);
+ pDevExt->MemBalloon.paMemObj[i] = NIL_RTR0MEMOBJ;
+ break;
+ }
+ pDevExt->MemBalloon.cChunks++;
+ }
+ }
+ else
+ {
+ /* deflate */
+ for (i = pDevExt->MemBalloon.cChunks; i-- > cBalloonChunks;)
+ {
+ rc = vgdrvBalloonDeflate(&pDevExt->MemBalloon.paMemObj[i], pReq);
+ if (RT_FAILURE(rc))
+ {
+ Log(("vboxGuestSetBalloonSize(deflate): failed, rc=%Rrc!\n", rc));
+ break;
+ }
+ pDevExt->MemBalloon.cChunks--;
+ }
+ }
+
+ VbglGRFree(&pReq->header);
+ }
+
+ /*
+ * Set the handle-in-ring3 indicator. When set Ring-3 will have to work
+ * the balloon changes via the other API.
+ */
+ *pfHandleInR3 = pDevExt->MemBalloon.fUseKernelAPI ? false : true;
+
+ return rc;
+}
+
+
+/**
+ * Inflate/deflate the balloon by one chunk.
+ *
+ * Worker for vgdrvIoCtl_ChangeMemoryBalloon - it takes the mutex.
+ *
+ * @returns VBox status code.
+ * @param pDevExt The device extension.
+ * @param pSession The session.
+ * @param u64ChunkAddr The address of the chunk to add to / remove from the
+ * balloon.
+ * @param fInflate Inflate if true, deflate if false.
+ */
+static int vgdrvSetBalloonSizeFromUser(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint64_t u64ChunkAddr, bool fInflate)
+{
+ VMMDevChangeMemBalloon *pReq;
+ PRTR0MEMOBJ pMemObj = NULL;
+ int rc = VINF_SUCCESS;
+ uint32_t i;
+ RT_NOREF1(pSession);
+
+ if (fInflate)
+ {
+ if ( pDevExt->MemBalloon.cChunks > pDevExt->MemBalloon.cMaxChunks - 1
+ || pDevExt->MemBalloon.cMaxChunks == 0 /* If called without first querying. */)
+ {
+ LogRel(("vboxGuestSetBalloonSize: cannot inflate balloon, already have %u chunks (max=%u)\n",
+ pDevExt->MemBalloon.cChunks, pDevExt->MemBalloon.cMaxChunks));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ if (!pDevExt->MemBalloon.paMemObj)
+ {
+ pDevExt->MemBalloon.paMemObj = (PRTR0MEMOBJ)RTMemAlloc(sizeof(RTR0MEMOBJ) * pDevExt->MemBalloon.cMaxChunks);
+ if (!pDevExt->MemBalloon.paMemObj)
+ {
+ LogRel(("VBoxGuestSetBalloonSizeFromUser: no memory for paMemObj!\n"));
+ return VERR_NO_MEMORY;
+ }
+ for (i = 0; i < pDevExt->MemBalloon.cMaxChunks; i++)
+ pDevExt->MemBalloon.paMemObj[i] = NIL_RTR0MEMOBJ;
+ }
+ }
+ else
+ {
+ if (pDevExt->MemBalloon.cChunks == 0)
+ {
+ AssertMsgFailed(("vboxGuestSetBalloonSize: cannot decrease balloon, already at size 0\n"));
+ return VERR_INVALID_PARAMETER;
+ }
+ }
+
+ /*
+ * Enumerate all memory objects and check if the object is already registered.
+ */
+ for (i = 0; i < pDevExt->MemBalloon.cMaxChunks; i++)
+ {
+ if ( fInflate
+ && !pMemObj
+ && pDevExt->MemBalloon.paMemObj[i] == NIL_RTR0MEMOBJ)
+ pMemObj = &pDevExt->MemBalloon.paMemObj[i]; /* found free object pointer */
+ if (RTR0MemObjAddressR3(pDevExt->MemBalloon.paMemObj[i]) == u64ChunkAddr)
+ {
+ if (fInflate)
+ return VERR_ALREADY_EXISTS; /* don't provide the same memory twice */
+ pMemObj = &pDevExt->MemBalloon.paMemObj[i];
+ break;
+ }
+ }
+ if (!pMemObj)
+ {
+ if (fInflate)
+ {
+ /* no free object pointer found -- should not happen */
+ return VERR_NO_MEMORY;
+ }
+
+ /* cannot free this memory as it wasn't provided before */
+ return VERR_NOT_FOUND;
+ }
+
+ /*
+ * Try inflate / default the balloon as requested.
+ */
+ rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, g_cbChangeMemBalloonReq, VMMDevReq_ChangeMemBalloon);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ if (fInflate)
+ {
+ rc = RTR0MemObjLockUser(pMemObj, (RTR3PTR)u64ChunkAddr, VMMDEV_MEMORY_BALLOON_CHUNK_SIZE,
+ RTMEM_PROT_READ | RTMEM_PROT_WRITE, NIL_RTR0PROCESS);
+ if (RT_SUCCESS(rc))
+ {
+ rc = vgdrvBalloonInflate(pMemObj, pReq);
+ if (RT_SUCCESS(rc))
+ pDevExt->MemBalloon.cChunks++;
+ else
+ {
+ Log(("vboxGuestSetBalloonSize(inflate): failed, rc=%Rrc!\n", rc));
+ RTR0MemObjFree(*pMemObj, true);
+ *pMemObj = NIL_RTR0MEMOBJ;
+ }
+ }
+ }
+ else
+ {
+ rc = vgdrvBalloonDeflate(pMemObj, pReq);
+ if (RT_SUCCESS(rc))
+ pDevExt->MemBalloon.cChunks--;
+ else
+ Log(("vboxGuestSetBalloonSize(deflate): failed, rc=%Rrc!\n", rc));
+ }
+
+ VbglGRFree(&pReq->header);
+ return rc;
+}
+
+
+/**
+ * Cleanup the memory balloon of a session.
+ *
+ * Will request the balloon mutex, so it must be valid and the caller must not
+ * own it already.
+ *
+ * @param pDevExt The device extension.
+ * @param pSession The session. Can be NULL at unload.
+ */
+static void vgdrvCloseMemBalloon(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession)
+{
+ RTSemFastMutexRequest(pDevExt->MemBalloon.hMtx);
+ if ( pDevExt->MemBalloon.pOwner == pSession
+ || pSession == NULL /*unload*/)
+ {
+ if (pDevExt->MemBalloon.paMemObj)
+ {
+ VMMDevChangeMemBalloon *pReq;
+ int rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, g_cbChangeMemBalloonReq, VMMDevReq_ChangeMemBalloon);
+ if (RT_SUCCESS(rc))
+ {
+ uint32_t i;
+ for (i = pDevExt->MemBalloon.cChunks; i-- > 0;)
+ {
+ rc = vgdrvBalloonDeflate(&pDevExt->MemBalloon.paMemObj[i], pReq);
+ if (RT_FAILURE(rc))
+ {
+ LogRel(("vgdrvCloseMemBalloon: Deflate failed with rc=%Rrc. Will leak %u chunks.\n",
+ rc, pDevExt->MemBalloon.cChunks));
+ break;
+ }
+ pDevExt->MemBalloon.paMemObj[i] = NIL_RTR0MEMOBJ;
+ pDevExt->MemBalloon.cChunks--;
+ }
+ VbglGRFree(&pReq->header);
+ }
+ else
+ LogRel(("vgdrvCloseMemBalloon: Failed to allocate VMMDev request buffer (rc=%Rrc). Will leak %u chunks.\n",
+ rc, pDevExt->MemBalloon.cChunks));
+ RTMemFree(pDevExt->MemBalloon.paMemObj);
+ pDevExt->MemBalloon.paMemObj = NULL;
+ }
+
+ pDevExt->MemBalloon.pOwner = NULL;
+ }
+ RTSemFastMutexRelease(pDevExt->MemBalloon.hMtx);
+}
+
+/** @} */
+
+
+
+/** @name Heartbeat
+ * @{
+ */
+
+/**
+ * Sends heartbeat to host.
+ *
+ * @returns VBox status code.
+ */
+static int vgdrvHeartbeatSend(PVBOXGUESTDEVEXT pDevExt)
+{
+ int rc;
+ if (pDevExt->pReqGuestHeartbeat)
+ {
+ rc = VbglGRPerform(pDevExt->pReqGuestHeartbeat);
+ Log3(("vgdrvHeartbeatSend: VbglGRPerform vgdrvHeartbeatSend completed with rc=%Rrc\n", rc));
+ }
+ else
+ rc = VERR_INVALID_STATE;
+ return rc;
+}
+
+
+/**
+ * Callback for heartbeat timer.
+ */
+static DECLCALLBACK(void) vgdrvHeartbeatTimerHandler(PRTTIMER hTimer, void *pvUser, uint64_t iTick)
+{
+ PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pvUser;
+ int rc;
+ AssertReturnVoid(pDevExt);
+
+ rc = vgdrvHeartbeatSend(pDevExt);
+ if (RT_FAILURE(rc))
+ Log(("HB Timer: vgdrvHeartbeatSend failed: rc=%Rrc\n", rc));
+
+ NOREF(hTimer); NOREF(iTick);
+}
+
+
+/**
+ * Configure the host to check guest's heartbeat
+ * and get heartbeat interval from the host.
+ *
+ * @returns VBox status code.
+ * @param pDevExt The device extension.
+ * @param fEnabled Set true to enable guest heartbeat checks on host.
+ */
+static int vgdrvHeartbeatHostConfigure(PVBOXGUESTDEVEXT pDevExt, bool fEnabled)
+{
+ VMMDevReqHeartbeat *pReq;
+ int rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_HeartbeatConfigure);
+ Log(("vgdrvHeartbeatHostConfigure: VbglGRAlloc vgdrvHeartbeatHostConfigure completed with rc=%Rrc\n", rc));
+ if (RT_SUCCESS(rc))
+ {
+ pReq->fEnabled = fEnabled;
+ pReq->cNsInterval = 0;
+ rc = VbglGRPerform(&pReq->header);
+ Log(("vgdrvHeartbeatHostConfigure: VbglGRPerform vgdrvHeartbeatHostConfigure completed with rc=%Rrc\n", rc));
+ pDevExt->cNsHeartbeatInterval = pReq->cNsInterval;
+ VbglGRFree(&pReq->header);
+ }
+ return rc;
+}
+
+
+/**
+ * Initializes the heartbeat timer.
+ *
+ * This feature may be disabled by the host.
+ *
+ * @returns VBox status (ignored).
+ * @param pDevExt The device extension.
+ */
+static int vgdrvHeartbeatInit(PVBOXGUESTDEVEXT pDevExt)
+{
+ /*
+ * Make sure that heartbeat checking is disabled.
+ */
+ int rc = vgdrvHeartbeatHostConfigure(pDevExt, false);
+ if (RT_SUCCESS(rc))
+ {
+ rc = vgdrvHeartbeatHostConfigure(pDevExt, true);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Preallocate the request to use it from the timer callback because:
+ * 1) on Windows VbglGRAlloc must be called at IRQL <= APC_LEVEL
+ * and the timer callback runs at DISPATCH_LEVEL;
+ * 2) avoid repeated allocations.
+ */
+ rc = VbglGRAlloc(&pDevExt->pReqGuestHeartbeat, sizeof(*pDevExt->pReqGuestHeartbeat), VMMDevReq_GuestHeartbeat);
+ if (RT_SUCCESS(rc))
+ {
+ LogRel(("vgdrvHeartbeatInit: Setting up heartbeat to trigger every %RU64 milliseconds\n",
+ pDevExt->cNsHeartbeatInterval / RT_NS_1MS));
+ rc = RTTimerCreateEx(&pDevExt->pHeartbeatTimer, pDevExt->cNsHeartbeatInterval, 0 /*fFlags*/,
+ (PFNRTTIMER)vgdrvHeartbeatTimerHandler, pDevExt);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTTimerStart(pDevExt->pHeartbeatTimer, 0);
+ if (RT_SUCCESS(rc))
+ return VINF_SUCCESS;
+
+ LogRel(("vgdrvHeartbeatInit: Heartbeat timer failed to start, rc=%Rrc\n", rc));
+ }
+ else
+ LogRel(("vgdrvHeartbeatInit: Failed to create heartbeat timer: %Rrc\n", rc));
+
+ VbglGRFree(pDevExt->pReqGuestHeartbeat);
+ pDevExt->pReqGuestHeartbeat = NULL;
+ }
+ else
+ LogRel(("vgdrvHeartbeatInit: VbglGRAlloc(VMMDevReq_GuestHeartbeat): %Rrc\n", rc));
+
+ LogRel(("vgdrvHeartbeatInit: Failed to set up the timer, guest heartbeat is disabled\n"));
+ vgdrvHeartbeatHostConfigure(pDevExt, false);
+ }
+ else
+ LogRel(("vgdrvHeartbeatInit: Failed to configure host for heartbeat checking: rc=%Rrc\n", rc));
+ }
+ return rc;
+}
+
+/** @} */
+
+
+/**
+ * Helper to reinit the VMMDev communication after hibernation.
+ *
+ * @returns VBox status code.
+ * @param pDevExt The device extension.
+ * @param enmOSType The OS type.
+ *
+ * @todo Call this on all platforms, not just windows.
+ */
+int VGDrvCommonReinitDevExtAfterHibernation(PVBOXGUESTDEVEXT pDevExt, VBOXOSTYPE enmOSType)
+{
+ int rc = vgdrvReportGuestInfo(enmOSType);
+ if (RT_SUCCESS(rc))
+ {
+ rc = vgdrvReportDriverStatus(true /* Driver is active */);
+ if (RT_FAILURE(rc))
+ Log(("VGDrvCommonReinitDevExtAfterHibernation: could not report guest driver status, rc=%Rrc\n", rc));
+ }
+ else
+ Log(("VGDrvCommonReinitDevExtAfterHibernation: could not report guest information to host, rc=%Rrc\n", rc));
+ LogFlow(("VGDrvCommonReinitDevExtAfterHibernation: returned with rc=%Rrc\n", rc));
+ RT_NOREF1(pDevExt);
+ return rc;
+}
+
+
+/**
+ * Initializes the VBoxGuest device extension when the
+ * device driver is loaded.
+ *
+ * The native code locates the VMMDev on the PCI bus and retrieve
+ * the MMIO and I/O port ranges, this function will take care of
+ * mapping the MMIO memory (if present). Upon successful return
+ * the native code should set up the interrupt handler.
+ *
+ * @returns VBox status code.
+ *
+ * @param pDevExt The device extension. Allocated by the native code.
+ * @param IOPortBase The base of the I/O port range.
+ * @param pvMMIOBase The base of the MMIO memory mapping.
+ * This is optional, pass NULL if not present.
+ * @param cbMMIO The size of the MMIO memory mapping.
+ * This is optional, pass 0 if not present.
+ * @param enmOSType The guest OS type to report to the VMMDev.
+ * @param fFixedEvents Events that will be enabled upon init and no client
+ * will ever be allowed to mask.
+ */
+int VGDrvCommonInitDevExt(PVBOXGUESTDEVEXT pDevExt, uint16_t IOPortBase,
+ void *pvMMIOBase, uint32_t cbMMIO, VBOXOSTYPE enmOSType, uint32_t fFixedEvents)
+{
+ int rc, rc2;
+
+#ifdef VBOX_GUESTDRV_WITH_RELEASE_LOGGER
+ /*
+ * Create the release log.
+ */
+ static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
+ PRTLOGGER pRelLogger;
+ rc = RTLogCreate(&pRelLogger, 0 /*fFlags*/, "all", "VBOXGUEST_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups,
+ RTLOGDEST_STDOUT | RTLOGDEST_DEBUGGER, NULL);
+ if (RT_SUCCESS(rc))
+ RTLogRelSetDefaultInstance(pRelLogger);
+ /** @todo Add native hook for getting logger config parameters and setting
+ * them. On linux we should use the module parameter stuff... */
+#endif
+
+ /*
+ * Adjust fFixedEvents.
+ */
+#ifdef VBOX_WITH_HGCM
+ fFixedEvents |= VMMDEV_EVENT_HGCM;
+#endif
+
+ /*
+ * Initialize the data.
+ */
+ pDevExt->IOPortBase = IOPortBase;
+ pDevExt->pVMMDevMemory = NULL;
+ pDevExt->hGuestMappings = NIL_RTR0MEMOBJ;
+ pDevExt->EventSpinlock = NIL_RTSPINLOCK;
+ pDevExt->pIrqAckEvents = NULL;
+ pDevExt->PhysIrqAckEvents = NIL_RTCCPHYS;
+ RTListInit(&pDevExt->WaitList);
+#ifdef VBOX_WITH_HGCM
+ RTListInit(&pDevExt->HGCMWaitList);
+#endif
+#ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
+ RTListInit(&pDevExt->WakeUpList);
+#endif
+ RTListInit(&pDevExt->WokenUpList);
+ RTListInit(&pDevExt->FreeList);
+ RTListInit(&pDevExt->SessionList);
+ pDevExt->cSessions = 0;
+ pDevExt->fLoggingEnabled = false;
+ pDevExt->f32PendingEvents = 0;
+ pDevExt->u32MousePosChangedSeq = 0;
+ pDevExt->SessionSpinlock = NIL_RTSPINLOCK;
+ pDevExt->MemBalloon.hMtx = NIL_RTSEMFASTMUTEX;
+ pDevExt->MemBalloon.cChunks = 0;
+ pDevExt->MemBalloon.cMaxChunks = 0;
+ pDevExt->MemBalloon.fUseKernelAPI = true;
+ pDevExt->MemBalloon.paMemObj = NULL;
+ pDevExt->MemBalloon.pOwner = NULL;
+ pDevExt->MouseNotifyCallback.pfnNotify = NULL;
+ pDevExt->MouseNotifyCallback.pvUser = NULL;
+ pDevExt->pReqGuestHeartbeat = NULL;
+
+ pDevExt->fFixedEvents = fFixedEvents;
+ vgdrvBitUsageTrackerClear(&pDevExt->EventFilterTracker);
+ pDevExt->fEventFilterHost = UINT32_MAX; /* forces a report */
+
+ vgdrvBitUsageTrackerClear(&pDevExt->MouseStatusTracker);
+ pDevExt->fMouseStatusHost = UINT32_MAX; /* forces a report */
+
+ pDevExt->fAcquireModeGuestCaps = 0;
+ pDevExt->fSetModeGuestCaps = 0;
+ pDevExt->fAcquiredGuestCaps = 0;
+ vgdrvBitUsageTrackerClear(&pDevExt->SetGuestCapsTracker);
+ pDevExt->fGuestCapsHost = UINT32_MAX; /* forces a report */
+
+ /*
+ * If there is an MMIO region validate the version and size.
+ */
+ if (pvMMIOBase)
+ {
+ VMMDevMemory *pVMMDev = (VMMDevMemory *)pvMMIOBase;
+ Assert(cbMMIO);
+ if ( pVMMDev->u32Version == VMMDEV_MEMORY_VERSION
+ && pVMMDev->u32Size >= 32
+ && pVMMDev->u32Size <= cbMMIO)
+ {
+ pDevExt->pVMMDevMemory = pVMMDev;
+ Log(("VGDrvCommonInitDevExt: VMMDevMemory: mapping=%p size=%#RX32 (%#RX32) version=%#RX32\n",
+ pVMMDev, pVMMDev->u32Size, cbMMIO, pVMMDev->u32Version));
+ }
+ else /* try live without it. */
+ LogRel(("VGDrvCommonInitDevExt: Bogus VMMDev memory; u32Version=%RX32 (expected %RX32) u32Size=%RX32 (expected <= %RX32)\n",
+ pVMMDev->u32Version, VMMDEV_MEMORY_VERSION, pVMMDev->u32Size, cbMMIO));
+ }
+
+ /*
+ * Create the wait and session spinlocks as well as the ballooning mutex.
+ */
+ rc = RTSpinlockCreate(&pDevExt->EventSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "VBoxGuestEvent");
+ if (RT_SUCCESS(rc))
+ rc = RTSpinlockCreate(&pDevExt->SessionSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "VBoxGuestSession");
+ if (RT_FAILURE(rc))
+ {
+ LogRel(("VGDrvCommonInitDevExt: failed to create spinlock, rc=%Rrc!\n", rc));
+ if (pDevExt->EventSpinlock != NIL_RTSPINLOCK)
+ RTSpinlockDestroy(pDevExt->EventSpinlock);
+ return rc;
+ }
+
+ rc = RTSemFastMutexCreate(&pDevExt->MemBalloon.hMtx);
+ if (RT_FAILURE(rc))
+ {
+ LogRel(("VGDrvCommonInitDevExt: failed to create mutex, rc=%Rrc!\n", rc));
+ RTSpinlockDestroy(pDevExt->SessionSpinlock);
+ RTSpinlockDestroy(pDevExt->EventSpinlock);
+ return rc;
+ }
+
+ /*
+ * Initialize the guest library and report the guest info back to VMMDev,
+ * set the interrupt control filter mask, and fixate the guest mappings
+ * made by the VMM.
+ */
+ rc = VbglInitPrimary(pDevExt->IOPortBase, (VMMDevMemory *)pDevExt->pVMMDevMemory);
+ if (RT_SUCCESS(rc))
+ {
+ rc = VbglGRAlloc((VMMDevRequestHeader **)&pDevExt->pIrqAckEvents, sizeof(VMMDevEvents), VMMDevReq_AcknowledgeEvents);
+ if (RT_SUCCESS(rc))
+ {
+ pDevExt->PhysIrqAckEvents = VbglPhysHeapGetPhysAddr(pDevExt->pIrqAckEvents);
+ Assert(pDevExt->PhysIrqAckEvents != 0);
+
+ rc = vgdrvReportGuestInfo(enmOSType);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Set the fixed event and make sure the host doesn't have any lingering
+ * the guest capabilities or mouse status bits set.
+ */
+ rc = vgdrvResetEventFilterOnHost(pDevExt, pDevExt->fFixedEvents);
+ if (RT_SUCCESS(rc))
+ {
+ rc = vgdrvResetCapabilitiesOnHost(pDevExt);
+ if (RT_SUCCESS(rc))
+ {
+ rc = vgdrvResetMouseStatusOnHost(pDevExt);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Initialize stuff which may fail without requiring the driver init to fail.
+ */
+ vgdrvInitFixateGuestMappings(pDevExt);
+ vgdrvHeartbeatInit(pDevExt);
+
+ /*
+ * Done!
+ */
+ rc = vgdrvReportDriverStatus(true /* Driver is active */);
+ if (RT_FAILURE(rc))
+ LogRel(("VGDrvCommonInitDevExt: VBoxReportGuestDriverStatus failed, rc=%Rrc\n", rc));
+
+ LogFlowFunc(("VGDrvCommonInitDevExt: returns success\n"));
+ return VINF_SUCCESS;
+ }
+ LogRel(("VGDrvCommonInitDevExt: failed to clear mouse status: rc=%Rrc\n", rc));
+ }
+ else
+ LogRel(("VGDrvCommonInitDevExt: failed to clear guest capabilities: rc=%Rrc\n", rc));
+ }
+ else
+ LogRel(("VGDrvCommonInitDevExt: failed to set fixed event filter: rc=%Rrc\n", rc));
+ }
+ else
+ LogRel(("VGDrvCommonInitDevExt: VBoxReportGuestInfo failed: rc=%Rrc\n", rc));
+ VbglGRFree((VMMDevRequestHeader *)pDevExt->pIrqAckEvents);
+ }
+ else
+ LogRel(("VGDrvCommonInitDevExt: VBoxGRAlloc failed: rc=%Rrc\n", rc));
+
+ VbglTerminate();
+ }
+ else
+ LogRel(("VGDrvCommonInitDevExt: VbglInit failed: rc=%Rrc\n", rc));
+
+ rc2 = RTSemFastMutexDestroy(pDevExt->MemBalloon.hMtx); AssertRC(rc2);
+ rc2 = RTSpinlockDestroy(pDevExt->EventSpinlock); AssertRC(rc2);
+ rc2 = RTSpinlockDestroy(pDevExt->SessionSpinlock); AssertRC(rc2);
+
+#ifdef VBOX_GUESTDRV_WITH_RELEASE_LOGGER
+ RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
+ RTLogDestroy(RTLogSetDefaultInstance(NULL));
+#endif
+ return rc; /* (failed) */
+}
+
+
+/**
+ * Deletes all the items in a wait chain.
+ * @param pList The head of the chain.
+ */
+static void vgdrvDeleteWaitList(PRTLISTNODE pList)
+{
+ while (!RTListIsEmpty(pList))
+ {
+ int rc2;
+ PVBOXGUESTWAIT pWait = RTListGetFirst(pList, VBOXGUESTWAIT, ListNode);
+ RTListNodeRemove(&pWait->ListNode);
+
+ rc2 = RTSemEventMultiDestroy(pWait->Event); AssertRC(rc2);
+ pWait->Event = NIL_RTSEMEVENTMULTI;
+ pWait->pSession = NULL;
+ RTMemFree(pWait);
+ }
+}
+
+
+/**
+ * Destroys the VBoxGuest device extension.
+ *
+ * The native code should call this before the driver is loaded,
+ * but don't call this on shutdown.
+ *
+ * @param pDevExt The device extension.
+ */
+void VGDrvCommonDeleteDevExt(PVBOXGUESTDEVEXT pDevExt)
+{
+ int rc2;
+ Log(("VGDrvCommonDeleteDevExt:\n"));
+ Log(("VBoxGuest: The additions driver is terminating.\n"));
+
+ /*
+ * Stop and destroy HB timer and
+ * disable host heartbeat checking.
+ */
+ if (pDevExt->pHeartbeatTimer)
+ {
+ RTTimerDestroy(pDevExt->pHeartbeatTimer);
+ vgdrvHeartbeatHostConfigure(pDevExt, false);
+ }
+
+ VbglGRFree(pDevExt->pReqGuestHeartbeat);
+ pDevExt->pReqGuestHeartbeat = NULL;
+
+ /*
+ * Clean up the bits that involves the host first.
+ */
+ vgdrvTermUnfixGuestMappings(pDevExt);
+ if (!RTListIsEmpty(&pDevExt->SessionList))
+ {
+ LogRelFunc(("session list not empty!\n"));
+ RTListInit(&pDevExt->SessionList);
+ }
+ /* Update the host flags (mouse status etc) not to reflect this session. */
+ pDevExt->fFixedEvents = 0;
+ vgdrvResetEventFilterOnHost(pDevExt, 0 /*fFixedEvents*/);
+ vgdrvResetCapabilitiesOnHost(pDevExt);
+ vgdrvResetMouseStatusOnHost(pDevExt);
+
+ vgdrvCloseMemBalloon(pDevExt, (PVBOXGUESTSESSION)NULL);
+
+ /*
+ * Cleanup all the other resources.
+ */
+ rc2 = RTSpinlockDestroy(pDevExt->EventSpinlock); AssertRC(rc2);
+ rc2 = RTSpinlockDestroy(pDevExt->SessionSpinlock); AssertRC(rc2);
+ rc2 = RTSemFastMutexDestroy(pDevExt->MemBalloon.hMtx); AssertRC(rc2);
+
+ vgdrvDeleteWaitList(&pDevExt->WaitList);
+#ifdef VBOX_WITH_HGCM
+ vgdrvDeleteWaitList(&pDevExt->HGCMWaitList);
+#endif
+#ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
+ vgdrvDeleteWaitList(&pDevExt->WakeUpList);
+#endif
+ vgdrvDeleteWaitList(&pDevExt->WokenUpList);
+ vgdrvDeleteWaitList(&pDevExt->FreeList);
+
+ VbglTerminate();
+
+ pDevExt->pVMMDevMemory = NULL;
+
+ pDevExt->IOPortBase = 0;
+ pDevExt->pIrqAckEvents = NULL;
+
+#ifdef VBOX_GUESTDRV_WITH_RELEASE_LOGGER
+ RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
+ RTLogDestroy(RTLogSetDefaultInstance(NULL));
+#endif
+
+}
+
+
+/**
+ * Creates a VBoxGuest user session.
+ *
+ * The native code calls this when a ring-3 client opens the device.
+ * Use VGDrvCommonCreateKernelSession when a ring-0 client connects.
+ *
+ * @returns VBox status code.
+ * @param pDevExt The device extension.
+ * @param ppSession Where to store the session on success.
+ */
+int VGDrvCommonCreateUserSession(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION *ppSession)
+{
+ PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)RTMemAllocZ(sizeof(*pSession));
+ if (RT_UNLIKELY(!pSession))
+ {
+ LogRel(("VGDrvCommonCreateUserSession: no memory!\n"));
+ return VERR_NO_MEMORY;
+ }
+
+ pSession->Process = RTProcSelf();
+ pSession->R0Process = RTR0ProcHandleSelf();
+ pSession->pDevExt = pDevExt;
+ RTSpinlockAcquire(pDevExt->SessionSpinlock);
+ RTListAppend(&pDevExt->SessionList, &pSession->ListNode);
+ pDevExt->cSessions++;
+ RTSpinlockRelease(pDevExt->SessionSpinlock);
+
+ *ppSession = pSession;
+ LogFlow(("VGDrvCommonCreateUserSession: pSession=%p proc=%RTproc (%d) r0proc=%p\n",
+ pSession, pSession->Process, (int)pSession->Process, (uintptr_t)pSession->R0Process)); /** @todo %RTr0proc */
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Creates a VBoxGuest kernel session.
+ *
+ * The native code calls this when a ring-0 client connects to the device.
+ * Use VGDrvCommonCreateUserSession when a ring-3 client opens the device.
+ *
+ * @returns VBox status code.
+ * @param pDevExt The device extension.
+ * @param ppSession Where to store the session on success.
+ */
+int VGDrvCommonCreateKernelSession(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION *ppSession)
+{
+ PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)RTMemAllocZ(sizeof(*pSession));
+ if (RT_UNLIKELY(!pSession))
+ {
+ LogRel(("VGDrvCommonCreateKernelSession: no memory!\n"));
+ return VERR_NO_MEMORY;
+ }
+
+ pSession->Process = NIL_RTPROCESS;
+ pSession->R0Process = NIL_RTR0PROCESS;
+ pSession->pDevExt = pDevExt;
+ RTSpinlockAcquire(pDevExt->SessionSpinlock);
+ RTListAppend(&pDevExt->SessionList, &pSession->ListNode);
+ pDevExt->cSessions++;
+ RTSpinlockRelease(pDevExt->SessionSpinlock);
+
+ *ppSession = pSession;
+ LogFlow(("VGDrvCommonCreateKernelSession: pSession=%p proc=%RTproc (%d) r0proc=%p\n",
+ pSession, pSession->Process, (int)pSession->Process, (uintptr_t)pSession->R0Process)); /** @todo %RTr0proc */
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Closes a VBoxGuest session.
+ *
+ * @param pDevExt The device extension.
+ * @param pSession The session to close (and free).
+ */
+void VGDrvCommonCloseSession(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession)
+{
+#ifdef VBOX_WITH_HGCM
+ unsigned i;
+#endif
+ LogFlow(("VGDrvCommonCloseSession: pSession=%p proc=%RTproc (%d) r0proc=%p\n",
+ pSession, pSession->Process, (int)pSession->Process, (uintptr_t)pSession->R0Process)); /** @todo %RTr0proc */
+
+ RTSpinlockAcquire(pDevExt->SessionSpinlock);
+ RTListNodeRemove(&pSession->ListNode);
+ pDevExt->cSessions--;
+ RTSpinlockRelease(pDevExt->SessionSpinlock);
+ vgdrvAcquireSessionCapabilities(pDevExt, pSession, 0, UINT32_MAX, VBOXGUESTCAPSACQUIRE_FLAGS_NONE,
+ true /*fSessionTermination*/);
+ vgdrvSetSessionCapabilities(pDevExt, pSession, 0 /*fOrMask*/, UINT32_MAX /*fNotMask*/, true /*fSessionTermination*/);
+ vgdrvSetSessionEventFilter(pDevExt, pSession, 0 /*fOrMask*/, UINT32_MAX /*fNotMask*/, true /*fSessionTermination*/);
+ vgdrvSetSessionMouseStatus(pDevExt, pSession, 0 /*fOrMask*/, UINT32_MAX /*fNotMask*/, true /*fSessionTermination*/);
+
+ vgdrvIoCtl_CancelAllWaitEvents(pDevExt, pSession);
+
+#ifdef VBOX_WITH_HGCM
+ for (i = 0; i < RT_ELEMENTS(pSession->aHGCMClientIds); i++)
+ if (pSession->aHGCMClientIds[i])
+ {
+ VBoxGuestHGCMDisconnectInfo Info;
+ Info.result = 0;
+ Info.u32ClientID = pSession->aHGCMClientIds[i];
+ pSession->aHGCMClientIds[i] = 0;
+ Log(("VGDrvCommonCloseSession: disconnecting client id %#RX32\n", Info.u32ClientID));
+ VbglR0HGCMInternalDisconnect(&Info, vgdrvHgcmAsyncWaitCallback, pDevExt, RT_INDEFINITE_WAIT);
+ }
+#endif
+
+ pSession->pDevExt = NULL;
+ pSession->Process = NIL_RTPROCESS;
+ pSession->R0Process = NIL_RTR0PROCESS;
+ vgdrvCloseMemBalloon(pDevExt, pSession);
+ RTMemFree(pSession);
+}
+
+
+/**
+ * Allocates a wait-for-event entry.
+ *
+ * @returns The wait-for-event entry.
+ * @param pDevExt The device extension.
+ * @param pSession The session that's allocating this. Can be NULL.
+ */
+static PVBOXGUESTWAIT vgdrvWaitAlloc(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession)
+{
+ /*
+ * Allocate it one way or the other.
+ */
+ PVBOXGUESTWAIT pWait = RTListGetFirst(&pDevExt->FreeList, VBOXGUESTWAIT, ListNode);
+ if (pWait)
+ {
+ RTSpinlockAcquire(pDevExt->EventSpinlock);
+
+ pWait = RTListGetFirst(&pDevExt->FreeList, VBOXGUESTWAIT, ListNode);
+ if (pWait)
+ RTListNodeRemove(&pWait->ListNode);
+
+ RTSpinlockRelease(pDevExt->EventSpinlock);
+ }
+ if (!pWait)
+ {
+ int rc;
+
+ pWait = (PVBOXGUESTWAIT)RTMemAlloc(sizeof(*pWait));
+ if (!pWait)
+ {
+ LogRelMax(32, ("vgdrvWaitAlloc: out-of-memory!\n"));
+ return NULL;
+ }
+
+ rc = RTSemEventMultiCreate(&pWait->Event);
+ if (RT_FAILURE(rc))
+ {
+ LogRelMax(32, ("vgdrvWaitAlloc: RTSemEventMultiCreate failed with rc=%Rrc!\n", rc));
+ RTMemFree(pWait);
+ return NULL;
+ }
+
+ pWait->ListNode.pNext = NULL;
+ pWait->ListNode.pPrev = NULL;
+ }
+
+ /*
+ * Zero members just as an precaution.
+ */
+ pWait->fReqEvents = 0;
+ pWait->fResEvents = 0;
+#ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
+ pWait->fPendingWakeUp = false;
+ pWait->fFreeMe = false;
+#endif
+ pWait->pSession = pSession;
+#ifdef VBOX_WITH_HGCM
+ pWait->pHGCMReq = NULL;
+#endif
+ RTSemEventMultiReset(pWait->Event);
+ return pWait;
+}
+
+
+/**
+ * Frees the wait-for-event entry.
+ *
+ * The caller must own the wait spinlock !
+ * The entry must be in a list!
+ *
+ * @param pDevExt The device extension.
+ * @param pWait The wait-for-event entry to free.
+ */
+static void vgdrvWaitFreeLocked(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTWAIT pWait)
+{
+ pWait->fReqEvents = 0;
+ pWait->fResEvents = 0;
+#ifdef VBOX_WITH_HGCM
+ pWait->pHGCMReq = NULL;
+#endif
+#ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
+ Assert(!pWait->fFreeMe);
+ if (pWait->fPendingWakeUp)
+ pWait->fFreeMe = true;
+ else
+#endif
+ {
+ RTListNodeRemove(&pWait->ListNode);
+ RTListAppend(&pDevExt->FreeList, &pWait->ListNode);
+ }
+}
+
+
+/**
+ * Frees the wait-for-event entry.
+ *
+ * @param pDevExt The device extension.
+ * @param pWait The wait-for-event entry to free.
+ */
+static void vgdrvWaitFreeUnlocked(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTWAIT pWait)
+{
+ RTSpinlockAcquire(pDevExt->EventSpinlock);
+ vgdrvWaitFreeLocked(pDevExt, pWait);
+ RTSpinlockRelease(pDevExt->EventSpinlock);
+}
+
+
+#ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
+/**
+ * Processes the wake-up list.
+ *
+ * All entries in the wake-up list gets signalled and moved to the woken-up
+ * list.
+ * At least on Windows this function can be invoked concurrently from
+ * different VCPUs. So, be thread-safe.
+ *
+ * @param pDevExt The device extension.
+ */
+void VGDrvCommonWaitDoWakeUps(PVBOXGUESTDEVEXT pDevExt)
+{
+ if (!RTListIsEmpty(&pDevExt->WakeUpList))
+ {
+ RTSpinlockAcquire(pDevExt->EventSpinlock);
+ for (;;)
+ {
+ int rc;
+ PVBOXGUESTWAIT pWait = RTListGetFirst(&pDevExt->WakeUpList, VBOXGUESTWAIT, ListNode);
+ if (!pWait)
+ break;
+ /* Prevent other threads from accessing pWait when spinlock is released. */
+ RTListNodeRemove(&pWait->ListNode);
+
+ pWait->fPendingWakeUp = true;
+ RTSpinlockRelease(pDevExt->EventSpinlock);
+
+ rc = RTSemEventMultiSignal(pWait->Event);
+ AssertRC(rc);
+
+ RTSpinlockAcquire(pDevExt->EventSpinlock);
+ Assert(pWait->ListNode.pNext == NULL && pWait->ListNode.pPrev == NULL);
+ RTListAppend(&pDevExt->WokenUpList, &pWait->ListNode);
+ pWait->fPendingWakeUp = false;
+ if (RT_LIKELY(!pWait->fFreeMe))
+ { /* likely */ }
+ else
+ {
+ pWait->fFreeMe = false;
+ vgdrvWaitFreeLocked(pDevExt, pWait);
+ }
+ }
+ RTSpinlockRelease(pDevExt->EventSpinlock);
+ }
+}
+#endif /* VBOXGUEST_USE_DEFERRED_WAKE_UP */
+
+
+/**
+ * Implements the fast (no input or output) type of IOCtls.
+ *
+ * This is currently just a placeholder stub inherited from the support driver code.
+ *
+ * @returns VBox status code.
+ * @param iFunction The IOCtl function number.
+ * @param pDevExt The device extension.
+ * @param pSession The session.
+ */
+int VGDrvCommonIoCtlFast(unsigned iFunction, PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession)
+{
+ LogFlow(("VGDrvCommonIoCtlFast: iFunction=%#x pDevExt=%p pSession=%p\n", iFunction, pDevExt, pSession));
+
+ NOREF(iFunction);
+ NOREF(pDevExt);
+ NOREF(pSession);
+ return VERR_NOT_SUPPORTED;
+}
+
+
+/**
+ * Return the VMM device port.
+ *
+ * returns IPRT status code.
+ * @param pDevExt The device extension.
+ * @param pInfo The request info.
+ * @param pcbDataReturned (out) contains the number of bytes to return.
+ */
+static int vgdrvIoCtl_GetVMMDevPort(PVBOXGUESTDEVEXT pDevExt, VBoxGuestPortInfo *pInfo, size_t *pcbDataReturned)
+{
+ LogFlow(("VBOXGUEST_IOCTL_GETVMMDEVPORT\n"));
+
+ pInfo->portAddress = pDevExt->IOPortBase;
+ pInfo->pVMMDevMemory = (VMMDevMemory *)pDevExt->pVMMDevMemory;
+ if (pcbDataReturned)
+ *pcbDataReturned = sizeof(*pInfo);
+ return VINF_SUCCESS;
+}
+
+
+#ifndef RT_OS_WINDOWS
+/**
+ * Set the callback for the kernel mouse handler.
+ *
+ * returns IPRT status code.
+ * @param pDevExt The device extension.
+ * @param pNotify The new callback information.
+ */
+int vgdrvIoCtl_SetMouseNotifyCallback(PVBOXGUESTDEVEXT pDevExt, VBoxGuestMouseSetNotifyCallback *pNotify)
+{
+ LogFlow(("VBOXGUEST_IOCTL_SET_MOUSE_NOTIFY_CALLBACK: pfnNotify=%p pvUser=%p\n", pNotify->pfnNotify, pNotify->pvUser));
+
+#ifdef VBOXGUEST_MOUSE_NOTIFY_CAN_PREEMPT
+ VGDrvNativeSetMouseNotifyCallback(pDevExt, pNotify);
+#else
+ RTSpinlockAcquire(pDevExt->EventSpinlock);
+ pDevExt->MouseNotifyCallback = *pNotify;
+ RTSpinlockRelease(pDevExt->EventSpinlock);
+#endif
+ return VINF_SUCCESS;
+}
+#endif
+
+
+/**
+ * Worker vgdrvIoCtl_WaitEvent.
+ *
+ * The caller enters the spinlock, we leave it.
+ *
+ * @returns VINF_SUCCESS if we've left the spinlock and can return immediately.
+ */
+DECLINLINE(int) vbdgCheckWaitEventCondition(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
+ VBoxGuestWaitEventInfo *pInfo, int iEvent, const uint32_t fReqEvents)
+{
+ uint32_t fMatches = pDevExt->f32PendingEvents & fReqEvents;
+ if (fMatches & VBOXGUEST_ACQUIRE_STYLE_EVENTS)
+ fMatches &= vgdrvGetAllowedEventMaskForSession(pDevExt, pSession);
+ if (fMatches || pSession->fPendingCancelWaitEvents)
+ {
+ ASMAtomicAndU32(&pDevExt->f32PendingEvents, ~fMatches);
+ RTSpinlockRelease(pDevExt->EventSpinlock);
+
+ pInfo->u32EventFlagsOut = fMatches;
+ pInfo->u32Result = VBOXGUEST_WAITEVENT_OK;
+ if (fReqEvents & ~((uint32_t)1 << iEvent))
+ LogFlow(("VBOXGUEST_IOCTL_WAITEVENT: returns %#x\n", pInfo->u32EventFlagsOut));
+ else
+ LogFlow(("VBOXGUEST_IOCTL_WAITEVENT: returns %#x/%d\n", pInfo->u32EventFlagsOut, iEvent));
+ pSession->fPendingCancelWaitEvents = false;
+ return VINF_SUCCESS;
+ }
+
+ RTSpinlockRelease(pDevExt->EventSpinlock);
+ return VERR_TIMEOUT;
+}
+
+
+static int vgdrvIoCtl_WaitEvent(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
+ VBoxGuestWaitEventInfo *pInfo, size_t *pcbDataReturned, bool fInterruptible)
+{
+ const uint32_t fReqEvents = pInfo->u32EventMaskIn;
+ uint32_t fResEvents;
+ int iEvent;
+ PVBOXGUESTWAIT pWait;
+ int rc;
+
+ pInfo->u32EventFlagsOut = 0;
+ pInfo->u32Result = VBOXGUEST_WAITEVENT_ERROR;
+ if (pcbDataReturned)
+ *pcbDataReturned = sizeof(*pInfo);
+
+ /*
+ * Copy and verify the input mask.
+ */
+ iEvent = ASMBitFirstSetU32(fReqEvents) - 1;
+ if (RT_UNLIKELY(iEvent < 0))
+ {
+ LogRel(("VBOXGUEST_IOCTL_WAITEVENT: Invalid input mask %#x!!\n", fReqEvents));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ /*
+ * Check the condition up front, before doing the wait-for-event allocations.
+ */
+ RTSpinlockAcquire(pDevExt->EventSpinlock);
+ rc = vbdgCheckWaitEventCondition(pDevExt, pSession, pInfo, iEvent, fReqEvents);
+ if (rc == VINF_SUCCESS)
+ return rc;
+
+ if (!pInfo->u32TimeoutIn)
+ {
+ pInfo->u32Result = VBOXGUEST_WAITEVENT_TIMEOUT;
+ LogFlow(("VBOXGUEST_IOCTL_WAITEVENT: returns VERR_TIMEOUT\n"));
+ return VERR_TIMEOUT;
+ }
+
+ pWait = vgdrvWaitAlloc(pDevExt, pSession);
+ if (!pWait)
+ return VERR_NO_MEMORY;
+ pWait->fReqEvents = fReqEvents;
+
+ /*
+ * We've got the wait entry now, re-enter the spinlock and check for the condition.
+ * If the wait condition is met, return.
+ * Otherwise enter into the list and go to sleep waiting for the ISR to signal us.
+ */
+ RTSpinlockAcquire(pDevExt->EventSpinlock);
+ RTListAppend(&pDevExt->WaitList, &pWait->ListNode);
+ rc = vbdgCheckWaitEventCondition(pDevExt, pSession, pInfo, iEvent, fReqEvents);
+ if (rc == VINF_SUCCESS)
+ {
+ vgdrvWaitFreeUnlocked(pDevExt, pWait);
+ return rc;
+ }
+
+ if (fInterruptible)
+ rc = RTSemEventMultiWaitNoResume(pWait->Event,
+ pInfo->u32TimeoutIn == UINT32_MAX ? RT_INDEFINITE_WAIT : pInfo->u32TimeoutIn);
+ else
+ rc = RTSemEventMultiWait(pWait->Event,
+ pInfo->u32TimeoutIn == UINT32_MAX ? RT_INDEFINITE_WAIT : pInfo->u32TimeoutIn);
+
+ /*
+ * There is one special case here and that's when the semaphore is
+ * destroyed upon device driver unload. This shouldn't happen of course,
+ * but in case it does, just get out of here ASAP.
+ */
+ if (rc == VERR_SEM_DESTROYED)
+ return rc;
+
+ /*
+ * Unlink the wait item and dispose of it.
+ */
+ RTSpinlockAcquire(pDevExt->EventSpinlock);
+ fResEvents = pWait->fResEvents;
+ vgdrvWaitFreeLocked(pDevExt, pWait);
+ RTSpinlockRelease(pDevExt->EventSpinlock);
+
+ /*
+ * Now deal with the return code.
+ */
+ if ( fResEvents
+ && fResEvents != UINT32_MAX)
+ {
+ pInfo->u32EventFlagsOut = fResEvents;
+ pInfo->u32Result = VBOXGUEST_WAITEVENT_OK;
+ if (fReqEvents & ~((uint32_t)1 << iEvent))
+ LogFlow(("VBOXGUEST_IOCTL_WAITEVENT: returns %#x\n", pInfo->u32EventFlagsOut));
+ else
+ LogFlow(("VBOXGUEST_IOCTL_WAITEVENT: returns %#x/%d\n", pInfo->u32EventFlagsOut, iEvent));
+ rc = VINF_SUCCESS;
+ }
+ else if ( fResEvents == UINT32_MAX
+ || rc == VERR_INTERRUPTED)
+ {
+ pInfo->u32Result = VBOXGUEST_WAITEVENT_INTERRUPTED;
+ rc = VERR_INTERRUPTED;
+ LogFlow(("VBOXGUEST_IOCTL_WAITEVENT: returns VERR_INTERRUPTED\n"));
+ }
+ else if (rc == VERR_TIMEOUT)
+ {
+ pInfo->u32Result = VBOXGUEST_WAITEVENT_TIMEOUT;
+ LogFlow(("VBOXGUEST_IOCTL_WAITEVENT: returns VERR_TIMEOUT (2)\n"));
+ }
+ else
+ {
+ if (RT_SUCCESS(rc))
+ {
+ LogRelMax(32, ("VBOXGUEST_IOCTL_WAITEVENT: returns %Rrc but no events!\n", rc));
+ rc = VERR_INTERNAL_ERROR;
+ }
+ pInfo->u32Result = VBOXGUEST_WAITEVENT_ERROR;
+ LogFlow(("VBOXGUEST_IOCTL_WAITEVENT: returns %Rrc\n", rc));
+ }
+
+ return rc;
+}
+
+
+static int vgdrvIoCtl_CancelAllWaitEvents(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession)
+{
+ PVBOXGUESTWAIT pWait;
+ PVBOXGUESTWAIT pSafe;
+ int rc = 0;
+ /* Was as least one WAITEVENT in process for this session? If not we
+ * set a flag that the next call should be interrupted immediately. This
+ * is needed so that a user thread can reliably interrupt another one in a
+ * WAITEVENT loop. */
+ bool fCancelledOne = false;
+
+ LogFlow(("VBOXGUEST_IOCTL_CANCEL_ALL_WAITEVENTS\n"));
+
+ /*
+ * Walk the event list and wake up anyone with a matching session.
+ */
+ RTSpinlockAcquire(pDevExt->EventSpinlock);
+ RTListForEachSafe(&pDevExt->WaitList, pWait, pSafe, VBOXGUESTWAIT, ListNode)
+ {
+ if (pWait->pSession == pSession)
+ {
+ fCancelledOne = true;
+ pWait->fResEvents = UINT32_MAX;
+ RTListNodeRemove(&pWait->ListNode);
+#ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
+ RTListAppend(&pDevExt->WakeUpList, &pWait->ListNode);
+#else
+ rc |= RTSemEventMultiSignal(pWait->Event);
+ RTListAppend(&pDevExt->WokenUpList, &pWait->ListNode);
+#endif
+ }
+ }
+ if (!fCancelledOne)
+ pSession->fPendingCancelWaitEvents = true;
+ RTSpinlockRelease(pDevExt->EventSpinlock);
+ Assert(rc == 0);
+ NOREF(rc);
+
+#ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
+ VGDrvCommonWaitDoWakeUps(pDevExt);
+#endif
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Checks if the VMM request is allowed in the context of the given session.
+ *
+ * @returns VINF_SUCCESS or VERR_PERMISSION_DENIED.
+ * @param pDevExt The device extension.
+ * @param pSession The calling session.
+ * @param enmType The request type.
+ * @param pReqHdr The request.
+ */
+static int vgdrvCheckIfVmmReqIsAllowed(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, VMMDevRequestType enmType,
+ VMMDevRequestHeader const *pReqHdr)
+{
+ /*
+ * Categorize the request being made.
+ */
+ /** @todo This need quite some more work! */
+ enum
+ {
+ kLevel_Invalid, kLevel_NoOne, kLevel_OnlyVBoxGuest, kLevel_OnlyKernel, kLevel_TrustedUsers, kLevel_AllUsers
+ } enmRequired;
+ RT_NOREF1(pDevExt);
+
+ switch (enmType)
+ {
+ /*
+ * Deny access to anything we don't know or provide specialized I/O controls for.
+ */
+#ifdef VBOX_WITH_HGCM
+ case VMMDevReq_HGCMConnect:
+ case VMMDevReq_HGCMDisconnect:
+# ifdef VBOX_WITH_64_BITS_GUESTS
+ case VMMDevReq_HGCMCall32:
+ case VMMDevReq_HGCMCall64:
+# else
+ case VMMDevReq_HGCMCall:
+# endif /* VBOX_WITH_64_BITS_GUESTS */
+ case VMMDevReq_HGCMCancel:
+ case VMMDevReq_HGCMCancel2:
+#endif /* VBOX_WITH_HGCM */
+ case VMMDevReq_SetGuestCapabilities:
+ default:
+ enmRequired = kLevel_NoOne;
+ break;
+
+ /*
+ * There are a few things only this driver can do (and it doesn't use
+ * the VMMRequst I/O control route anyway, but whatever).
+ */
+ case VMMDevReq_ReportGuestInfo:
+ case VMMDevReq_ReportGuestInfo2:
+ case VMMDevReq_GetHypervisorInfo:
+ case VMMDevReq_SetHypervisorInfo:
+ case VMMDevReq_RegisterPatchMemory:
+ case VMMDevReq_DeregisterPatchMemory:
+ case VMMDevReq_GetMemBalloonChangeRequest:
+ enmRequired = kLevel_OnlyVBoxGuest;
+ break;
+
+ /*
+ * Trusted users apps only.
+ */
+ case VMMDevReq_QueryCredentials:
+ case VMMDevReq_ReportCredentialsJudgement:
+ case VMMDevReq_RegisterSharedModule:
+ case VMMDevReq_UnregisterSharedModule:
+ case VMMDevReq_WriteCoreDump:
+ case VMMDevReq_GetCpuHotPlugRequest:
+ case VMMDevReq_SetCpuHotPlugStatus:
+ case VMMDevReq_CheckSharedModules:
+ case VMMDevReq_GetPageSharingStatus:
+ case VMMDevReq_DebugIsPageShared:
+ case VMMDevReq_ReportGuestStats:
+ case VMMDevReq_ReportGuestUserState:
+ case VMMDevReq_GetStatisticsChangeRequest:
+ case VMMDevReq_ChangeMemBalloon:
+ enmRequired = kLevel_TrustedUsers;
+ break;
+
+ /*
+ * Anyone.
+ */
+ case VMMDevReq_GetMouseStatus:
+ case VMMDevReq_SetMouseStatus:
+ case VMMDevReq_SetPointerShape:
+ case VMMDevReq_GetHostVersion:
+ case VMMDevReq_Idle:
+ case VMMDevReq_GetHostTime:
+ case VMMDevReq_SetPowerStatus:
+ case VMMDevReq_AcknowledgeEvents:
+ case VMMDevReq_CtlGuestFilterMask:
+ case VMMDevReq_ReportGuestStatus:
+ case VMMDevReq_GetDisplayChangeRequest:
+ case VMMDevReq_VideoModeSupported:
+ case VMMDevReq_GetHeightReduction:
+ case VMMDevReq_GetDisplayChangeRequest2:
+ case VMMDevReq_VideoModeSupported2:
+ case VMMDevReq_VideoAccelEnable:
+ case VMMDevReq_VideoAccelFlush:
+ case VMMDevReq_VideoSetVisibleRegion:
+ case VMMDevReq_GetDisplayChangeRequestEx:
+ case VMMDevReq_GetSeamlessChangeRequest:
+ case VMMDevReq_GetVRDPChangeRequest:
+ case VMMDevReq_LogString:
+ case VMMDevReq_GetSessionId:
+ enmRequired = kLevel_AllUsers;
+ break;
+
+ /*
+ * Depends on the request parameters...
+ */
+ /** @todo this have to be changed into an I/O control and the facilities
+ * tracked in the session so they can automatically be failed when the
+ * session terminates without reporting the new status.
+ *
+ * The information presented by IGuest is not reliable without this! */
+ case VMMDevReq_ReportGuestCapabilities:
+ switch (((VMMDevReportGuestStatus const *)pReqHdr)->guestStatus.facility)
+ {
+ case VBoxGuestFacilityType_All:
+ case VBoxGuestFacilityType_VBoxGuestDriver:
+ enmRequired = kLevel_OnlyVBoxGuest;
+ break;
+ case VBoxGuestFacilityType_VBoxService:
+ enmRequired = kLevel_TrustedUsers;
+ break;
+ case VBoxGuestFacilityType_VBoxTrayClient:
+ case VBoxGuestFacilityType_Seamless:
+ case VBoxGuestFacilityType_Graphics:
+ default:
+ enmRequired = kLevel_AllUsers;
+ break;
+ }
+ break;
+ }
+
+ /*
+ * Check against the session.
+ */
+ switch (enmRequired)
+ {
+ default:
+ case kLevel_NoOne:
+ break;
+ case kLevel_OnlyVBoxGuest:
+ case kLevel_OnlyKernel:
+ if (pSession->R0Process == NIL_RTR0PROCESS)
+ return VINF_SUCCESS;
+ break;
+ case kLevel_TrustedUsers:
+ case kLevel_AllUsers:
+ return VINF_SUCCESS;
+ }
+
+ return VERR_PERMISSION_DENIED;
+}
+
+static int vgdrvIoCtl_VMMRequest(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
+ VMMDevRequestHeader *pReqHdr, size_t cbData, size_t *pcbDataReturned)
+{
+ int rc;
+ VMMDevRequestHeader *pReqCopy;
+
+ /*
+ * Validate the header and request size.
+ */
+ const VMMDevRequestType enmType = pReqHdr->requestType;
+ const uint32_t cbReq = pReqHdr->size;
+ const uint32_t cbMinSize = (uint32_t)vmmdevGetRequestSize(enmType);
+
+ LogFlow(("VBOXGUEST_IOCTL_VMMREQUEST: type %d\n", pReqHdr->requestType));
+
+ if (cbReq < cbMinSize)
+ {
+ LogRel(("VBOXGUEST_IOCTL_VMMREQUEST: invalid hdr size %#x, expected >= %#x; type=%#x!!\n",
+ cbReq, cbMinSize, enmType));
+ return VERR_INVALID_PARAMETER;
+ }
+ if (cbReq > cbData)
+ {
+ LogRel(("VBOXGUEST_IOCTL_VMMREQUEST: invalid size %#x, expected >= %#x (hdr); type=%#x!!\n",
+ cbData, cbReq, enmType));
+ return VERR_INVALID_PARAMETER;
+ }
+ rc = VbglGRVerify(pReqHdr, cbData);
+ if (RT_FAILURE(rc))
+ {
+ Log(("VBOXGUEST_IOCTL_VMMREQUEST: invalid header: size %#x, expected >= %#x (hdr); type=%#x; rc=%Rrc!!\n",
+ cbData, cbReq, enmType, rc));
+ return rc;
+ }
+
+ rc = vgdrvCheckIfVmmReqIsAllowed(pDevExt, pSession, enmType, pReqHdr);
+ if (RT_FAILURE(rc))
+ {
+ Log(("VBOXGUEST_IOCTL_VMMREQUEST: Operation not allowed! type=%#x rc=%Rrc\n", enmType, rc));
+ return rc;
+ }
+
+ /*
+ * Make a copy of the request in the physical memory heap so
+ * the VBoxGuestLibrary can more easily deal with the request.
+ * (This is really a waste of time since the OS or the OS specific
+ * code has already buffered or locked the input/output buffer, but
+ * it does makes things a bit simpler wrt to phys address.)
+ */
+ rc = VbglGRAlloc(&pReqCopy, cbReq, enmType);
+ if (RT_FAILURE(rc))
+ {
+ Log(("VBOXGUEST_IOCTL_VMMREQUEST: failed to allocate %u (%#x) bytes to cache the request. rc=%Rrc!!\n",
+ cbReq, cbReq, rc));
+ return rc;
+ }
+ memcpy(pReqCopy, pReqHdr, cbReq);
+
+ if (enmType == VMMDevReq_GetMouseStatus) /* clear poll condition. */
+ pSession->u32MousePosChangedSeq = ASMAtomicUoReadU32(&pDevExt->u32MousePosChangedSeq);
+
+ rc = VbglGRPerform(pReqCopy);
+ if ( RT_SUCCESS(rc)
+ && RT_SUCCESS(pReqCopy->rc))
+ {
+ Assert(rc != VINF_HGCM_ASYNC_EXECUTE);
+ Assert(pReqCopy->rc != VINF_HGCM_ASYNC_EXECUTE);
+
+ memcpy(pReqHdr, pReqCopy, cbReq);
+ if (pcbDataReturned)
+ *pcbDataReturned = cbReq;
+ }
+ else if (RT_FAILURE(rc))
+ Log(("VBOXGUEST_IOCTL_VMMREQUEST: VbglGRPerform - rc=%Rrc!\n", rc));
+ else
+ {
+ Log(("VBOXGUEST_IOCTL_VMMREQUEST: request execution failed; VMMDev rc=%Rrc!\n", pReqCopy->rc));
+ rc = pReqCopy->rc;
+ }
+
+ VbglGRFree(pReqCopy);
+ return rc;
+}
+
+
+#ifdef VBOX_WITH_HGCM
+
+AssertCompile(RT_INDEFINITE_WAIT == (uint32_t)RT_INDEFINITE_WAIT); /* assumed by code below */
+
+/** Worker for vgdrvHgcmAsyncWaitCallback*. */
+static int vgdrvHgcmAsyncWaitCallbackWorker(VMMDevHGCMRequestHeader volatile *pHdr, PVBOXGUESTDEVEXT pDevExt,
+ bool fInterruptible, uint32_t cMillies)
+{
+ int rc;
+
+ /*
+ * Check to see if the condition was met by the time we got here.
+ *
+ * We create a simple poll loop here for dealing with out-of-memory
+ * conditions since the caller isn't necessarily able to deal with
+ * us returning too early.
+ */
+ PVBOXGUESTWAIT pWait;
+ for (;;)
+ {
+ RTSpinlockAcquire(pDevExt->EventSpinlock);
+ if ((pHdr->fu32Flags & VBOX_HGCM_REQ_DONE) != 0)
+ {
+ RTSpinlockRelease(pDevExt->EventSpinlock);
+ return VINF_SUCCESS;
+ }
+ RTSpinlockRelease(pDevExt->EventSpinlock);
+
+ pWait = vgdrvWaitAlloc(pDevExt, NULL);
+ if (pWait)
+ break;
+ if (fInterruptible)
+ return VERR_INTERRUPTED;
+ RTThreadSleep(1);
+ }
+ pWait->fReqEvents = VMMDEV_EVENT_HGCM;
+ pWait->pHGCMReq = pHdr;
+
+ /*
+ * Re-enter the spinlock and re-check for the condition.
+ * If the condition is met, return.
+ * Otherwise link us into the HGCM wait list and go to sleep.
+ */
+ RTSpinlockAcquire(pDevExt->EventSpinlock);
+ RTListAppend(&pDevExt->HGCMWaitList, &pWait->ListNode);
+ if ((pHdr->fu32Flags & VBOX_HGCM_REQ_DONE) != 0)
+ {
+ vgdrvWaitFreeLocked(pDevExt, pWait);
+ RTSpinlockRelease(pDevExt->EventSpinlock);
+ return VINF_SUCCESS;
+ }
+ RTSpinlockRelease(pDevExt->EventSpinlock);
+
+ if (fInterruptible)
+ rc = RTSemEventMultiWaitNoResume(pWait->Event, cMillies);
+ else
+ rc = RTSemEventMultiWait(pWait->Event, cMillies);
+ if (rc == VERR_SEM_DESTROYED)
+ return rc;
+
+ /*
+ * Unlink, free and return.
+ */
+ if ( RT_FAILURE(rc)
+ && rc != VERR_TIMEOUT
+ && ( !fInterruptible
+ || rc != VERR_INTERRUPTED))
+ LogRel(("vgdrvHgcmAsyncWaitCallback: wait failed! %Rrc\n", rc));
+
+ vgdrvWaitFreeUnlocked(pDevExt, pWait);
+ return rc;
+}
+
+
+/**
+ * This is a callback for dealing with async waits.
+ *
+ * It operates in a manner similar to vgdrvIoCtl_WaitEvent.
+ */
+static DECLCALLBACK(int) vgdrvHgcmAsyncWaitCallback(VMMDevHGCMRequestHeader *pHdr, void *pvUser, uint32_t u32User)
+{
+ PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pvUser;
+ LogFlow(("vgdrvHgcmAsyncWaitCallback: requestType=%d\n", pHdr->header.requestType));
+ return vgdrvHgcmAsyncWaitCallbackWorker((VMMDevHGCMRequestHeader volatile *)pHdr, pDevExt,
+ false /* fInterruptible */, u32User /* cMillies */);
+}
+
+
+/**
+ * This is a callback for dealing with async waits with a timeout.
+ *
+ * It operates in a manner similar to vgdrvIoCtl_WaitEvent.
+ */
+static DECLCALLBACK(int) vgdrvHgcmAsyncWaitCallbackInterruptible(VMMDevHGCMRequestHeader *pHdr, void *pvUser, uint32_t u32User)
+{
+ PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pvUser;
+ LogFlow(("vgdrvHgcmAsyncWaitCallbackInterruptible: requestType=%d\n", pHdr->header.requestType));
+ return vgdrvHgcmAsyncWaitCallbackWorker((VMMDevHGCMRequestHeader volatile *)pHdr, pDevExt,
+ true /* fInterruptible */, u32User /* cMillies */);
+}
+
+
+static int vgdrvIoCtl_HGCMConnect(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
+ VBoxGuestHGCMConnectInfo *pInfo, size_t *pcbDataReturned)
+{
+ int rc;
+
+ /*
+ * The VbglHGCMConnect call will invoke the callback if the HGCM
+ * call is performed in an ASYNC fashion. The function is not able
+ * to deal with cancelled requests.
+ */
+ Log(("VBOXGUEST_IOCTL_HGCM_CONNECT: %.128s\n",
+ pInfo->Loc.type == VMMDevHGCMLoc_LocalHost || pInfo->Loc.type == VMMDevHGCMLoc_LocalHost_Existing
+ ? pInfo->Loc.u.host.achName : "<not local host>"));
+
+ rc = VbglR0HGCMInternalConnect(pInfo, vgdrvHgcmAsyncWaitCallback, pDevExt, RT_INDEFINITE_WAIT);
+ if (RT_SUCCESS(rc))
+ {
+ Log(("VBOXGUEST_IOCTL_HGCM_CONNECT: u32Client=%RX32 result=%Rrc (rc=%Rrc)\n",
+ pInfo->u32ClientID, pInfo->result, rc));
+ if (RT_SUCCESS(pInfo->result))
+ {
+ /*
+ * Append the client id to the client id table.
+ * If the table has somehow become filled up, we'll disconnect the session.
+ */
+ unsigned i;
+ RTSpinlockAcquire(pDevExt->SessionSpinlock);
+ for (i = 0; i < RT_ELEMENTS(pSession->aHGCMClientIds); i++)
+ if (!pSession->aHGCMClientIds[i])
+ {
+ pSession->aHGCMClientIds[i] = pInfo->u32ClientID;
+ break;
+ }
+ RTSpinlockRelease(pDevExt->SessionSpinlock);
+ if (i >= RT_ELEMENTS(pSession->aHGCMClientIds))
+ {
+ VBoxGuestHGCMDisconnectInfo Info;
+ LogRelMax(32, ("VBOXGUEST_IOCTL_HGCM_CONNECT: too many HGCMConnect calls for one session!\n"));
+ Info.result = 0;
+ Info.u32ClientID = pInfo->u32ClientID;
+ VbglR0HGCMInternalDisconnect(&Info, vgdrvHgcmAsyncWaitCallback, pDevExt, RT_INDEFINITE_WAIT);
+ return VERR_TOO_MANY_OPEN_FILES;
+ }
+ }
+ else
+ rc = pInfo->result;
+ if (pcbDataReturned)
+ *pcbDataReturned = sizeof(*pInfo);
+ }
+ return rc;
+}
+
+
+static int vgdrvIoCtl_HGCMDisconnect(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
+ VBoxGuestHGCMDisconnectInfo *pInfo, size_t *pcbDataReturned)
+{
+ /*
+ * Validate the client id and invalidate its entry while we're in the call.
+ */
+ int rc;
+ const uint32_t u32ClientId = pInfo->u32ClientID;
+ unsigned i;
+ RTSpinlockAcquire(pDevExt->SessionSpinlock);
+ for (i = 0; i < RT_ELEMENTS(pSession->aHGCMClientIds); i++)
+ if (pSession->aHGCMClientIds[i] == u32ClientId)
+ {
+ pSession->aHGCMClientIds[i] = UINT32_MAX;
+ break;
+ }
+ RTSpinlockRelease(pDevExt->SessionSpinlock);
+ if (i >= RT_ELEMENTS(pSession->aHGCMClientIds))
+ {
+ LogRelMax(32, ("VBOXGUEST_IOCTL_HGCM_DISCONNECT: u32Client=%RX32\n", u32ClientId));
+ return VERR_INVALID_HANDLE;
+ }
+
+ /*
+ * The VbglHGCMConnect call will invoke the callback if the HGCM
+ * call is performed in an ASYNC fashion. The function is not able
+ * to deal with cancelled requests.
+ */
+ Log(("VBOXGUEST_IOCTL_HGCM_DISCONNECT: u32Client=%RX32\n", pInfo->u32ClientID));
+ rc = VbglR0HGCMInternalDisconnect(pInfo, vgdrvHgcmAsyncWaitCallback, pDevExt, RT_INDEFINITE_WAIT);
+ if (RT_SUCCESS(rc))
+ {
+ LogFlow(("VBOXGUEST_IOCTL_HGCM_DISCONNECT: result=%Rrc\n", pInfo->result));
+ if (pcbDataReturned)
+ *pcbDataReturned = sizeof(*pInfo);
+ }
+
+ /* Update the client id array according to the result. */
+ RTSpinlockAcquire(pDevExt->SessionSpinlock);
+ if (pSession->aHGCMClientIds[i] == UINT32_MAX)
+ pSession->aHGCMClientIds[i] = RT_SUCCESS(rc) && RT_SUCCESS(pInfo->result) ? 0 : u32ClientId;
+ RTSpinlockRelease(pDevExt->SessionSpinlock);
+
+ return rc;
+}
+
+
+static int vgdrvIoCtl_HGCMCall(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, VBoxGuestHGCMCallInfo *pInfo,
+ uint32_t cMillies, bool fInterruptible, bool f32bit, bool fUserData,
+ size_t cbExtra, size_t cbData, size_t *pcbDataReturned)
+{
+ const uint32_t u32ClientId = pInfo->u32ClientID;
+ uint32_t fFlags;
+ size_t cbActual;
+ unsigned i;
+ int rc;
+
+ /*
+ * Some more validations.
+ */
+ if (pInfo->cParms > 4096) /* (Just make sure it doesn't overflow the next check.) */
+ {
+ LogRel(("VBOXGUEST_IOCTL_HGCM_CALL: cParm=%RX32 is not sane\n", pInfo->cParms));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ cbActual = cbExtra + sizeof(*pInfo);
+#ifdef RT_ARCH_AMD64
+ if (f32bit)
+ cbActual += pInfo->cParms * sizeof(HGCMFunctionParameter32);
+ else
+#endif
+ cbActual += pInfo->cParms * sizeof(HGCMFunctionParameter);
+ if (cbData < cbActual)
+ {
+ LogRel(("VBOXGUEST_IOCTL_HGCM_CALL: cbData=%#zx (%zu) required size is %#zx (%zu)\n",
+ cbData, cbData, cbActual, cbActual));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ /*
+ * Validate the client id.
+ */
+ RTSpinlockAcquire(pDevExt->SessionSpinlock);
+ for (i = 0; i < RT_ELEMENTS(pSession->aHGCMClientIds); i++)
+ if (pSession->aHGCMClientIds[i] == u32ClientId)
+ break;
+ RTSpinlockRelease(pDevExt->SessionSpinlock);
+ if (RT_UNLIKELY(i >= RT_ELEMENTS(pSession->aHGCMClientIds)))
+ {
+ LogRelMax(32, ("VBOXGUEST_IOCTL_HGCM_CALL: Invalid handle. u32Client=%RX32\n", u32ClientId));
+ return VERR_INVALID_HANDLE;
+ }
+
+ /*
+ * The VbglHGCMCall call will invoke the callback if the HGCM
+ * call is performed in an ASYNC fashion. This function can
+ * deal with cancelled requests, so we let user more requests
+ * be interruptible (should add a flag for this later I guess).
+ */
+ LogFlow(("VBOXGUEST_IOCTL_HGCM_CALL: u32Client=%RX32\n", pInfo->u32ClientID));
+ fFlags = !fUserData && pSession->R0Process == NIL_RTR0PROCESS ? VBGLR0_HGCMCALL_F_KERNEL : VBGLR0_HGCMCALL_F_USER;
+ uint32_t cbInfo = (uint32_t)(cbData - cbExtra);
+#ifdef RT_ARCH_AMD64
+ if (f32bit)
+ {
+ if (fInterruptible)
+ rc = VbglR0HGCMInternalCall32(pInfo, cbInfo, fFlags, vgdrvHgcmAsyncWaitCallbackInterruptible, pDevExt, cMillies);
+ else
+ rc = VbglR0HGCMInternalCall32(pInfo, cbInfo, fFlags, vgdrvHgcmAsyncWaitCallback, pDevExt, cMillies);
+ }
+ else
+#endif
+ {
+ if (fInterruptible)
+ rc = VbglR0HGCMInternalCall(pInfo, cbInfo, fFlags, vgdrvHgcmAsyncWaitCallbackInterruptible, pDevExt, cMillies);
+ else
+ rc = VbglR0HGCMInternalCall(pInfo, cbInfo, fFlags, vgdrvHgcmAsyncWaitCallback, pDevExt, cMillies);
+ }
+ if (RT_SUCCESS(rc))
+ {
+ LogFlow(("VBOXGUEST_IOCTL_HGCM_CALL: result=%Rrc\n", pInfo->result));
+ if (pcbDataReturned)
+ *pcbDataReturned = cbActual;
+ }
+ else
+ {
+ if ( rc != VERR_INTERRUPTED
+ && rc != VERR_TIMEOUT)
+ LogRelMax(32, ("VBOXGUEST_IOCTL_HGCM_CALL: %s Failed. rc=%Rrc.\n", f32bit ? "32" : "64", rc));
+ else
+ Log(("VBOXGUEST_IOCTL_HGCM_CALL: %s Failed. rc=%Rrc.\n", f32bit ? "32" : "64", rc));
+ }
+ return rc;
+}
+
+#endif /* VBOX_WITH_HGCM */
+
+/**
+ * Handle VBOXGUEST_IOCTL_CHECK_BALLOON from R3.
+ *
+ * Ask the host for the size of the balloon and try to set it accordingly. If
+ * this approach fails because it's not supported, return with fHandleInR3 set
+ * and let the user land supply memory we can lock via the other ioctl.
+ *
+ * @returns VBox status code.
+ *
+ * @param pDevExt The device extension.
+ * @param pSession The session.
+ * @param pInfo The output buffer.
+ * @param pcbDataReturned Where to store the amount of returned data. Can
+ * be NULL.
+ */
+static int vgdrvIoCtl_CheckMemoryBalloon(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
+ VBoxGuestCheckBalloonInfo *pInfo, size_t *pcbDataReturned)
+{
+ VMMDevGetMemBalloonChangeRequest *pReq;
+ int rc;
+
+ LogFlow(("VBOXGUEST_IOCTL_CHECK_BALLOON:\n"));
+ rc = RTSemFastMutexRequest(pDevExt->MemBalloon.hMtx);
+ AssertRCReturn(rc, rc);
+
+ /*
+ * The first user trying to query/change the balloon becomes the
+ * owner and owns it until the session is closed (vgdrvCloseMemBalloon).
+ */
+ if ( pDevExt->MemBalloon.pOwner != pSession
+ && pDevExt->MemBalloon.pOwner == NULL)
+ pDevExt->MemBalloon.pOwner = pSession;
+
+ if (pDevExt->MemBalloon.pOwner == pSession)
+ {
+ rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(VMMDevGetMemBalloonChangeRequest), VMMDevReq_GetMemBalloonChangeRequest);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * This is a response to that event. Setting this bit means that
+ * we request the value from the host and change the guest memory
+ * balloon according to this value.
+ */
+ pReq->eventAck = VMMDEV_EVENT_BALLOON_CHANGE_REQUEST;
+ rc = VbglGRPerform(&pReq->header);
+ if (RT_SUCCESS(rc))
+ {
+ Assert(pDevExt->MemBalloon.cMaxChunks == pReq->cPhysMemChunks || pDevExt->MemBalloon.cMaxChunks == 0);
+ pDevExt->MemBalloon.cMaxChunks = pReq->cPhysMemChunks;
+
+ pInfo->cBalloonChunks = pReq->cBalloonChunks;
+ pInfo->fHandleInR3 = false;
+
+ rc = vgdrvSetBalloonSizeKernel(pDevExt, pReq->cBalloonChunks, &pInfo->fHandleInR3);
+ /* Ignore various out of memory failures. */
+ if ( rc == VERR_NO_MEMORY
+ || rc == VERR_NO_PHYS_MEMORY
+ || rc == VERR_NO_CONT_MEMORY)
+ rc = VINF_SUCCESS;
+
+ if (pcbDataReturned)
+ *pcbDataReturned = sizeof(VBoxGuestCheckBalloonInfo);
+ }
+ else
+ LogRel(("VBOXGUEST_IOCTL_CHECK_BALLOON: VbglGRPerform failed. rc=%Rrc\n", rc));
+ VbglGRFree(&pReq->header);
+ }
+ }
+ else
+ rc = VERR_PERMISSION_DENIED;
+
+ RTSemFastMutexRelease(pDevExt->MemBalloon.hMtx);
+ LogFlow(("VBOXGUEST_IOCTL_CHECK_BALLOON returns %Rrc\n", rc));
+ return rc;
+}
+
+
+/**
+ * Handle a request for changing the memory balloon.
+ *
+ * @returns VBox status code.
+ *
+ * @param pDevExt The device extention.
+ * @param pSession The session.
+ * @param pInfo The change request structure (input).
+ * @param pcbDataReturned Where to store the amount of returned data. Can
+ * be NULL.
+ */
+static int vgdrvIoCtl_ChangeMemoryBalloon(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
+ VBoxGuestChangeBalloonInfo *pInfo, size_t *pcbDataReturned)
+{
+ int rc;
+ LogFlow(("VBOXGUEST_IOCTL_CHANGE_BALLOON: fInflate=%RTbool u64ChunkAddr=%#RX64\n", pInfo->fInflate, pInfo->u64ChunkAddr));
+
+ rc = RTSemFastMutexRequest(pDevExt->MemBalloon.hMtx);
+ AssertRCReturn(rc, rc);
+
+ if (!pDevExt->MemBalloon.fUseKernelAPI)
+ {
+ /*
+ * The first user trying to query/change the balloon becomes the
+ * owner and owns it until the session is closed (vgdrvCloseMemBalloon).
+ */
+ if ( pDevExt->MemBalloon.pOwner != pSession
+ && pDevExt->MemBalloon.pOwner == NULL)
+ pDevExt->MemBalloon.pOwner = pSession;
+
+ if (pDevExt->MemBalloon.pOwner == pSession)
+ {
+ rc = vgdrvSetBalloonSizeFromUser(pDevExt, pSession, pInfo->u64ChunkAddr, !!pInfo->fInflate);
+ if (pcbDataReturned)
+ *pcbDataReturned = 0;
+ }
+ else
+ rc = VERR_PERMISSION_DENIED;
+ }
+ else
+ rc = VERR_PERMISSION_DENIED;
+
+ RTSemFastMutexRelease(pDevExt->MemBalloon.hMtx);
+ return rc;
+}
+
+
+/**
+ * Handle a request for writing a core dump of the guest on the host.
+ *
+ * @returns VBox status code.
+ *
+ * @param pDevExt The device extension.
+ * @param pInfo The output buffer.
+ */
+static int vgdrvIoCtl_WriteCoreDump(PVBOXGUESTDEVEXT pDevExt, VBoxGuestWriteCoreDump *pInfo)
+{
+ VMMDevReqWriteCoreDump *pReq = NULL;
+ int rc;
+ LogFlow(("VBOXGUEST_IOCTL_WRITE_CORE_DUMP\n"));
+ RT_NOREF1(pDevExt);
+
+ rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_WriteCoreDump);
+ if (RT_SUCCESS(rc))
+ {
+ pReq->fFlags = pInfo->fFlags;
+ rc = VbglGRPerform(&pReq->header);
+ if (RT_FAILURE(rc))
+ Log(("VBOXGUEST_IOCTL_WRITE_CORE_DUMP: VbglGRPerform failed, rc=%Rrc!\n", rc));
+
+ VbglGRFree(&pReq->header);
+ }
+ else
+ Log(("VBOXGUEST_IOCTL_WRITE_CORE_DUMP: failed to allocate %u (%#x) bytes to cache the request. rc=%Rrc!!\n",
+ sizeof(*pReq), sizeof(*pReq), rc));
+ return rc;
+}
+
+
+/**
+ * Guest backdoor logging.
+ *
+ * @returns VBox status code.
+ *
+ * @param pDevExt The device extension.
+ * @param pch The log message (need not be NULL terminated).
+ * @param cbData Size of the buffer.
+ * @param pcbDataReturned Where to store the amount of returned data. Can be NULL.
+ * @param fUserSession Copy of VBOXGUESTSESSION::fUserSession for the
+ * call. True normal user, false root user.
+ */
+static int vgdrvIoCtl_Log(PVBOXGUESTDEVEXT pDevExt, const char *pch, size_t cbData, size_t *pcbDataReturned, bool fUserSession)
+{
+ if (pDevExt->fLoggingEnabled)
+ RTLogBackdoorPrintf("%.*s", cbData, pch);
+ else if (!fUserSession)
+ LogRel(("%.*s", cbData, pch));
+ else
+ Log(("%.*s", cbData, pch));
+ if (pcbDataReturned)
+ *pcbDataReturned = 0;
+ return VINF_SUCCESS;
+}
+
+
+/** @name Guest Capabilities, Mouse Status and Event Filter
+ * @{
+ */
+
+/**
+ * Clears a bit usage tracker (init time).
+ *
+ * @param pTracker The tracker to clear.
+ */
+static void vgdrvBitUsageTrackerClear(PVBOXGUESTBITUSAGETRACER pTracker)
+{
+ uint32_t iBit;
+ AssertCompile(sizeof(pTracker->acPerBitUsage) == 32 * sizeof(uint32_t));
+
+ for (iBit = 0; iBit < 32; iBit++)
+ pTracker->acPerBitUsage[iBit] = 0;
+ pTracker->fMask = 0;
+}
+
+
+#ifdef VBOX_STRICT
+/**
+ * Checks that pTracker->fMask is correct and that the usage values are within
+ * the valid range.
+ *
+ * @param pTracker The tracker.
+ * @param cMax Max valid usage value.
+ * @param pszWhat Identifies the tracker in assertions.
+ */
+static void vgdrvBitUsageTrackerCheckMask(PCVBOXGUESTBITUSAGETRACER pTracker, uint32_t cMax, const char *pszWhat)
+{
+ uint32_t fMask = 0;
+ uint32_t iBit;
+ AssertCompile(sizeof(pTracker->acPerBitUsage) == 32 * sizeof(uint32_t));
+
+ for (iBit = 0; iBit < 32; iBit++)
+ if (pTracker->acPerBitUsage[iBit])
+ {
+ fMask |= RT_BIT_32(iBit);
+ AssertMsg(pTracker->acPerBitUsage[iBit] <= cMax,
+ ("%s: acPerBitUsage[%u]=%#x cMax=%#x\n", pszWhat, iBit, pTracker->acPerBitUsage[iBit], cMax));
+ }
+
+ AssertMsg(fMask == pTracker->fMask, ("%s: %#x vs %#x\n", pszWhat, fMask, pTracker->fMask));
+}
+#endif
+
+
+/**
+ * Applies a change to the bit usage tracker.
+ *
+ *
+ * @returns true if the mask changed, false if not.
+ * @param pTracker The bit usage tracker.
+ * @param fChanged The bits to change.
+ * @param fPrevious The previous value of the bits.
+ * @param cMax The max valid usage value for assertions.
+ * @param pszWhat Identifies the tracker in assertions.
+ */
+static bool vgdrvBitUsageTrackerChange(PVBOXGUESTBITUSAGETRACER pTracker, uint32_t fChanged, uint32_t fPrevious,
+ uint32_t cMax, const char *pszWhat)
+{
+ bool fGlobalChange = false;
+ AssertCompile(sizeof(pTracker->acPerBitUsage) == 32 * sizeof(uint32_t));
+
+ while (fChanged)
+ {
+ uint32_t const iBit = ASMBitFirstSetU32(fChanged) - 1;
+ uint32_t const fBitMask = RT_BIT_32(iBit);
+ Assert(iBit < 32); Assert(fBitMask & fChanged);
+
+ if (fBitMask & fPrevious)
+ {
+ pTracker->acPerBitUsage[iBit] -= 1;
+ AssertMsg(pTracker->acPerBitUsage[iBit] <= cMax,
+ ("%s: acPerBitUsage[%u]=%#x cMax=%#x\n", pszWhat, iBit, pTracker->acPerBitUsage[iBit], cMax));
+ if (pTracker->acPerBitUsage[iBit] == 0)
+ {
+ fGlobalChange = true;
+ pTracker->fMask &= ~fBitMask;
+ }
+ }
+ else
+ {
+ pTracker->acPerBitUsage[iBit] += 1;
+ AssertMsg(pTracker->acPerBitUsage[iBit] > 0 && pTracker->acPerBitUsage[iBit] <= cMax,
+ ("pTracker->acPerBitUsage[%u]=%#x cMax=%#x\n", pszWhat, iBit, pTracker->acPerBitUsage[iBit], cMax));
+ if (pTracker->acPerBitUsage[iBit] == 1)
+ {
+ fGlobalChange = true;
+ pTracker->fMask |= fBitMask;
+ }
+ }
+
+ fChanged &= ~fBitMask;
+ }
+
+#ifdef VBOX_STRICT
+ vgdrvBitUsageTrackerCheckMask(pTracker, cMax, pszWhat);
+#endif
+ NOREF(pszWhat); NOREF(cMax);
+ return fGlobalChange;
+}
+
+
+/**
+ * Init and termination worker for resetting the (host) event filter on the host
+ *
+ * @returns VBox status code.
+ * @param pDevExt The device extension.
+ * @param fFixedEvents Fixed events (init time).
+ */
+static int vgdrvResetEventFilterOnHost(PVBOXGUESTDEVEXT pDevExt, uint32_t fFixedEvents)
+{
+ VMMDevCtlGuestFilterMask *pReq;
+ int rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_CtlGuestFilterMask);
+ if (RT_SUCCESS(rc))
+ {
+ pReq->u32NotMask = UINT32_MAX & ~fFixedEvents;
+ pReq->u32OrMask = fFixedEvents;
+ rc = VbglGRPerform(&pReq->header);
+ if (RT_FAILURE(rc))
+ LogRelFunc(("failed with rc=%Rrc\n", rc));
+ VbglGRFree(&pReq->header);
+ }
+ RT_NOREF1(pDevExt);
+ return rc;
+}
+
+
+/**
+ * Changes the event filter mask for the given session.
+ *
+ * This is called in response to VBOXGUEST_IOCTL_CTL_FILTER_MASK as well as to
+ * do session cleanup.
+ *
+ * @returns VBox status code.
+ * @param pDevExt The device extension.
+ * @param pSession The session.
+ * @param fOrMask The events to add.
+ * @param fNotMask The events to remove.
+ * @param fSessionTermination Set if we're called by the session cleanup code.
+ * This tweaks the error handling so we perform
+ * proper session cleanup even if the host
+ * misbehaves.
+ *
+ * @remarks Takes the session spinlock.
+ */
+static int vgdrvSetSessionEventFilter(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
+ uint32_t fOrMask, uint32_t fNotMask, bool fSessionTermination)
+{
+ VMMDevCtlGuestFilterMask *pReq;
+ uint32_t fChanged;
+ uint32_t fPrevious;
+ int rc;
+
+ /*
+ * Preallocate a request buffer so we can do all in one go without leaving the spinlock.
+ */
+ rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_CtlGuestFilterMask);
+ if (RT_SUCCESS(rc))
+ { /* nothing */ }
+ else if (!fSessionTermination)
+ {
+ LogRel(("vgdrvSetSessionFilterMask: VbglGRAlloc failure: %Rrc\n", rc));
+ return rc;
+ }
+ else
+ pReq = NULL; /* Ignore failure, we must do session cleanup. */
+
+
+ RTSpinlockAcquire(pDevExt->SessionSpinlock);
+
+ /*
+ * Apply the changes to the session mask.
+ */
+ fPrevious = pSession->fEventFilter;
+ pSession->fEventFilter |= fOrMask;
+ pSession->fEventFilter &= ~fNotMask;
+
+ /*
+ * If anything actually changed, update the global usage counters.
+ */
+ fChanged = fPrevious ^ pSession->fEventFilter;
+ if (fChanged)
+ {
+ bool fGlobalChange = vgdrvBitUsageTrackerChange(&pDevExt->EventFilterTracker, fChanged, fPrevious,
+ pDevExt->cSessions, "EventFilterTracker");
+
+ /*
+ * If there are global changes, update the event filter on the host.
+ */
+ if (fGlobalChange || pDevExt->fEventFilterHost == UINT32_MAX)
+ {
+ Assert(pReq || fSessionTermination);
+ if (pReq)
+ {
+ pReq->u32OrMask = pDevExt->fFixedEvents | pDevExt->EventFilterTracker.fMask;
+ if (pReq->u32OrMask == pDevExt->fEventFilterHost)
+ rc = VINF_SUCCESS;
+ else
+ {
+ pDevExt->fEventFilterHost = pReq->u32OrMask;
+ pReq->u32NotMask = ~pReq->u32OrMask;
+ rc = VbglGRPerform(&pReq->header);
+ if (RT_FAILURE(rc))
+ {
+ /*
+ * Failed, roll back (unless it's session termination time).
+ */
+ pDevExt->fEventFilterHost = UINT32_MAX;
+ if (!fSessionTermination)
+ {
+ vgdrvBitUsageTrackerChange(&pDevExt->EventFilterTracker, fChanged, pSession->fEventFilter,
+ pDevExt->cSessions, "EventFilterTracker");
+ pSession->fEventFilter = fPrevious;
+ }
+ }
+ }
+ }
+ else
+ rc = VINF_SUCCESS;
+ }
+ }
+
+ RTSpinlockRelease(pDevExt->SessionSpinlock);
+ if (pReq)
+ VbglGRFree(&pReq->header);
+ return rc;
+}
+
+
+/**
+ * Handle VBOXGUEST_IOCTL_CTL_FILTER_MASK.
+ *
+ * @returns VBox status code.
+ *
+ * @param pDevExt The device extension.
+ * @param pSession The session.
+ * @param pInfo The request.
+ */
+static int vgdrvIoCtl_CtlFilterMask(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, VBoxGuestFilterMaskInfo *pInfo)
+{
+ LogFlow(("VBOXGUEST_IOCTL_CTL_FILTER_MASK: or=%#x not=%#x\n", pInfo->u32OrMask, pInfo->u32NotMask));
+
+ if ((pInfo->u32OrMask | pInfo->u32NotMask) & ~VMMDEV_EVENT_VALID_EVENT_MASK)
+ {
+ Log(("VBOXGUEST_IOCTL_CTL_FILTER_MASK: or=%#x not=%#x: Invalid masks!\n", pInfo->u32OrMask, pInfo->u32NotMask));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ return vgdrvSetSessionEventFilter(pDevExt, pSession, pInfo->u32OrMask, pInfo->u32NotMask, false /*fSessionTermination*/);
+}
+
+
+/**
+ * Init and termination worker for set mouse feature status to zero on the host.
+ *
+ * @returns VBox status code.
+ * @param pDevExt The device extension.
+ */
+static int vgdrvResetMouseStatusOnHost(PVBOXGUESTDEVEXT pDevExt)
+{
+ VMMDevReqMouseStatus *pReq;
+ int rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_SetMouseStatus);
+ if (RT_SUCCESS(rc))
+ {
+ pReq->mouseFeatures = 0;
+ pReq->pointerXPos = 0;
+ pReq->pointerYPos = 0;
+ rc = VbglGRPerform(&pReq->header);
+ if (RT_FAILURE(rc))
+ LogRelFunc(("failed with rc=%Rrc\n", rc));
+ VbglGRFree(&pReq->header);
+ }
+ RT_NOREF1(pDevExt);
+ return rc;
+}
+
+
+/**
+ * Changes the mouse status mask for the given session.
+ *
+ * This is called in response to VBOXGUEST_IOCTL_SET_MOUSE_STATUS as well as to
+ * do session cleanup.
+ *
+ * @returns VBox status code.
+ * @param pDevExt The device extension.
+ * @param pSession The session.
+ * @param fOrMask The status flags to add.
+ * @param fNotMask The status flags to remove.
+ * @param fSessionTermination Set if we're called by the session cleanup code.
+ * This tweaks the error handling so we perform
+ * proper session cleanup even if the host
+ * misbehaves.
+ *
+ * @remarks Takes the session spinlock.
+ */
+static int vgdrvSetSessionMouseStatus(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
+ uint32_t fOrMask, uint32_t fNotMask, bool fSessionTermination)
+{
+ VMMDevReqMouseStatus *pReq;
+ uint32_t fChanged;
+ uint32_t fPrevious;
+ int rc;
+
+ /*
+ * Preallocate a request buffer so we can do all in one go without leaving the spinlock.
+ */
+ rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_SetMouseStatus);
+ if (RT_SUCCESS(rc))
+ { /* nothing */ }
+ else if (!fSessionTermination)
+ {
+ LogRel(("vgdrvSetSessionMouseStatus: VbglGRAlloc failure: %Rrc\n", rc));
+ return rc;
+ }
+ else
+ pReq = NULL; /* Ignore failure, we must do session cleanup. */
+
+
+ RTSpinlockAcquire(pDevExt->SessionSpinlock);
+
+ /*
+ * Apply the changes to the session mask.
+ */
+ fPrevious = pSession->fMouseStatus;
+ pSession->fMouseStatus |= fOrMask;
+ pSession->fMouseStatus &= ~fNotMask;
+
+ /*
+ * If anything actually changed, update the global usage counters.
+ */
+ fChanged = fPrevious ^ pSession->fMouseStatus;
+ if (fChanged)
+ {
+ bool fGlobalChange = vgdrvBitUsageTrackerChange(&pDevExt->MouseStatusTracker, fChanged, fPrevious,
+ pDevExt->cSessions, "MouseStatusTracker");
+
+ /*
+ * If there are global changes, update the event filter on the host.
+ */
+ if (fGlobalChange || pDevExt->fMouseStatusHost == UINT32_MAX)
+ {
+ Assert(pReq || fSessionTermination);
+ if (pReq)
+ {
+ pReq->mouseFeatures = pDevExt->MouseStatusTracker.fMask;
+ if (pReq->mouseFeatures == pDevExt->fMouseStatusHost)
+ rc = VINF_SUCCESS;
+ else
+ {
+ pDevExt->fMouseStatusHost = pReq->mouseFeatures;
+ pReq->pointerXPos = 0;
+ pReq->pointerYPos = 0;
+ rc = VbglGRPerform(&pReq->header);
+ if (RT_FAILURE(rc))
+ {
+ /*
+ * Failed, roll back (unless it's session termination time).
+ */
+ pDevExt->fMouseStatusHost = UINT32_MAX;
+ if (!fSessionTermination)
+ {
+ vgdrvBitUsageTrackerChange(&pDevExt->MouseStatusTracker, fChanged, pSession->fMouseStatus,
+ pDevExt->cSessions, "MouseStatusTracker");
+ pSession->fMouseStatus = fPrevious;
+ }
+ }
+ }
+ }
+ else
+ rc = VINF_SUCCESS;
+ }
+ }
+
+ RTSpinlockRelease(pDevExt->SessionSpinlock);
+ if (pReq)
+ VbglGRFree(&pReq->header);
+ return rc;
+}
+
+
+/**
+ * Sets the mouse status features for this session and updates them globally.
+ *
+ * @returns VBox status code.
+ *
+ * @param pDevExt The device extention.
+ * @param pSession The session.
+ * @param fFeatures New bitmap of enabled features.
+ */
+static int vgdrvIoCtl_SetMouseStatus(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t fFeatures)
+{
+ LogFlow(("VBOXGUEST_IOCTL_SET_MOUSE_STATUS: features=%#x\n", fFeatures));
+
+ if (fFeatures & ~VMMDEV_MOUSE_GUEST_MASK)
+ return VERR_INVALID_PARAMETER;
+
+ return vgdrvSetSessionMouseStatus(pDevExt, pSession, fFeatures, ~fFeatures, false /*fSessionTermination*/);
+}
+
+
+/**
+ * Return the mask of VMM device events that this session is allowed to see (wrt
+ * to "acquire" mode guest capabilities).
+ *
+ * The events associated with guest capabilities in "acquire" mode will be
+ * restricted to sessions which has acquired the respective capabilities.
+ * If someone else tries to wait for acquired events, they won't be woken up
+ * when the event becomes pending. Should some other thread in the session
+ * acquire the capability while the corresponding event is pending, the waiting
+ * thread will woken up.
+ *
+ * @returns Mask of events valid for the given session.
+ * @param pDevExt The device extension.
+ * @param pSession The session.
+ *
+ * @remarks Needs only be called when dispatching events in the
+ * VBOXGUEST_ACQUIRE_STYLE_EVENTS mask.
+ */
+static uint32_t vgdrvGetAllowedEventMaskForSession(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession)
+{
+ uint32_t fAcquireModeGuestCaps;
+ uint32_t fAcquiredGuestCaps;
+ uint32_t fAllowedEvents;
+
+ /*
+ * Note! Reads pSession->fAcquiredGuestCaps and pDevExt->fAcquireModeGuestCaps
+ * WITHOUT holding VBOXGUESTDEVEXT::SessionSpinlock.
+ */
+ fAcquireModeGuestCaps = ASMAtomicUoReadU32(&pDevExt->fAcquireModeGuestCaps);
+ if (fAcquireModeGuestCaps == 0)
+ return VMMDEV_EVENT_VALID_EVENT_MASK;
+ fAcquiredGuestCaps = ASMAtomicUoReadU32(&pSession->fAcquiredGuestCaps);
+
+ /*
+ * Calculate which events to allow according to the cap config and caps
+ * acquired by the session.
+ */
+ fAllowedEvents = VMMDEV_EVENT_VALID_EVENT_MASK;
+ if ( !(fAcquiredGuestCaps & VMMDEV_GUEST_SUPPORTS_GRAPHICS)
+ && (fAcquireModeGuestCaps & VMMDEV_GUEST_SUPPORTS_GRAPHICS))
+ fAllowedEvents &= ~VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST;
+
+ if ( !(fAcquiredGuestCaps & VMMDEV_GUEST_SUPPORTS_SEAMLESS)
+ && (fAcquireModeGuestCaps & VMMDEV_GUEST_SUPPORTS_SEAMLESS))
+ fAllowedEvents &= ~VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST;
+
+ return fAllowedEvents;
+}
+
+
+/**
+ * Init and termination worker for set guest capabilities to zero on the host.
+ *
+ * @returns VBox status code.
+ * @param pDevExt The device extension.
+ */
+static int vgdrvResetCapabilitiesOnHost(PVBOXGUESTDEVEXT pDevExt)
+{
+ VMMDevReqGuestCapabilities2 *pReq;
+ int rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_SetGuestCapabilities);
+ if (RT_SUCCESS(rc))
+ {
+ pReq->u32NotMask = UINT32_MAX;
+ pReq->u32OrMask = 0;
+ rc = VbglGRPerform(&pReq->header);
+
+ if (RT_FAILURE(rc))
+ LogRelFunc(("failed with rc=%Rrc\n", rc));
+ VbglGRFree(&pReq->header);
+ }
+ RT_NOREF1(pDevExt);
+ return rc;
+}
+
+
+/**
+ * Sets the guest capabilities to the host while holding the lock.
+ *
+ * This will ASSUME that we're the ones in charge of the mask, so
+ * we'll simply clear all bits we don't set.
+ *
+ * @returns VBox status code.
+ * @param pDevExt The device extension.
+ * @param pReq The request.
+ */
+static int vgdrvUpdateCapabilitiesOnHostWithReqAndLock(PVBOXGUESTDEVEXT pDevExt, VMMDevReqGuestCapabilities2 *pReq)
+{
+ int rc;
+
+ pReq->u32OrMask = pDevExt->fAcquiredGuestCaps | pDevExt->SetGuestCapsTracker.fMask;
+ if (pReq->u32OrMask == pDevExt->fGuestCapsHost)
+ rc = VINF_SUCCESS;
+ else
+ {
+ pDevExt->fGuestCapsHost = pReq->u32OrMask;
+ pReq->u32NotMask = ~pReq->u32OrMask;
+ rc = VbglGRPerform(&pReq->header);
+ if (RT_FAILURE(rc))
+ pDevExt->fGuestCapsHost = UINT32_MAX;
+ }
+
+ return rc;
+}
+
+
+/**
+ * Switch a set of capabilities into "acquire" mode and (maybe) acquire them for
+ * the given session.
+ *
+ * This is called in response to VBOXGUEST_IOCTL_GUEST_CAPS_ACQUIRE as well as
+ * to do session cleanup.
+ *
+ * @returns VBox status code.
+ * @param pDevExt The device extension.
+ * @param pSession The session.
+ * @param fOrMask The capabilities to add .
+ * @param fNotMask The capabilities to remove. Ignored in
+ * VBOXGUESTCAPSACQUIRE_FLAGS_CONFIG_ACQUIRE_MODE.
+ * @param enmFlags Confusing operation modifier.
+ * VBOXGUESTCAPSACQUIRE_FLAGS_NONE means to both
+ * configure and acquire/release the capabilities.
+ * VBOXGUESTCAPSACQUIRE_FLAGS_CONFIG_ACQUIRE_MODE
+ * means only configure capabilities in the
+ * @a fOrMask capabilities for "acquire" mode.
+ * @param fSessionTermination Set if we're called by the session cleanup code.
+ * This tweaks the error handling so we perform
+ * proper session cleanup even if the host
+ * misbehaves.
+ *
+ * @remarks Takes both the session and event spinlocks.
+ */
+static int vgdrvAcquireSessionCapabilities(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
+ uint32_t fOrMask, uint32_t fNotMask, VBOXGUESTCAPSACQUIRE_FLAGS enmFlags,
+ bool fSessionTermination)
+{
+ uint32_t fCurrentOwnedCaps;
+ uint32_t fSessionRemovedCaps;
+ uint32_t fSessionAddedCaps;
+ uint32_t fOtherConflictingCaps;
+ VMMDevReqGuestCapabilities2 *pReq = NULL;
+ int rc;
+
+
+ /*
+ * Validate and adjust input.
+ */
+ if (fOrMask & ~( VMMDEV_GUEST_SUPPORTS_SEAMLESS
+ | VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING
+ | VMMDEV_GUEST_SUPPORTS_GRAPHICS ) )
+ {
+ LogRel(("vgdrvAcquireSessionCapabilities: pSession=%p fOrMask=%#x fNotMask=%#x enmFlags=%#x -- invalid fOrMask\n",
+ pSession, fOrMask, fNotMask, enmFlags));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ if ( enmFlags != VBOXGUESTCAPSACQUIRE_FLAGS_CONFIG_ACQUIRE_MODE
+ && enmFlags != VBOXGUESTCAPSACQUIRE_FLAGS_NONE)
+ {
+ LogRel(("vgdrvAcquireSessionCapabilities: pSession=%p fOrMask=%#x fNotMask=%#x enmFlags=%#x: invalid enmFlags %d\n",
+ pSession, fOrMask, fNotMask, enmFlags));
+ return VERR_INVALID_PARAMETER;
+ }
+ Assert(!fOrMask || !fSessionTermination);
+
+ /* The fNotMask no need to have all values valid, invalid ones will simply be ignored. */
+ fNotMask &= ~fOrMask;
+
+ /*
+ * Preallocate a update request if we're about to do more than just configure
+ * the capability mode.
+ */
+ if (enmFlags != VBOXGUESTCAPSACQUIRE_FLAGS_CONFIG_ACQUIRE_MODE)
+ {
+ rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_SetGuestCapabilities);
+ if (RT_SUCCESS(rc))
+ { /* do nothing */ }
+ else if (!fSessionTermination)
+ {
+ LogRel(("vgdrvAcquireSessionCapabilities: pSession=%p fOrMask=%#x fNotMask=%#x enmFlags=%#x: VbglGRAlloc failure: %Rrc\n",
+ pSession, fOrMask, fNotMask, enmFlags, rc));
+ return rc;
+ }
+ else
+ pReq = NULL; /* Ignore failure, we must do session cleanup. */
+ }
+
+ /*
+ * Try switch the capabilities in the OR mask into "acquire" mode.
+ *
+ * Note! We currently ignore anyone which may already have "set" the capabilities
+ * in fOrMask. Perhaps not the best way to handle it, but it's simple...
+ */
+ RTSpinlockAcquire(pDevExt->EventSpinlock);
+
+ if (!(pDevExt->fSetModeGuestCaps & fOrMask))
+ pDevExt->fAcquireModeGuestCaps |= fOrMask;
+ else
+ {
+ RTSpinlockRelease(pDevExt->EventSpinlock);
+
+ if (pReq)
+ VbglGRFree(&pReq->header);
+ AssertMsgFailed(("Trying to change caps mode: %#x\n", fOrMask));
+ LogRel(("vgdrvAcquireSessionCapabilities: pSession=%p fOrMask=%#x fNotMask=%#x enmFlags=%#x: calling caps acquire for set caps\n",
+ pSession, fOrMask, fNotMask, enmFlags));
+ return VERR_INVALID_STATE;
+ }
+
+ /*
+ * If we only wanted to switch the capabilities into "acquire" mode, we're done now.
+ */
+ if (enmFlags & VBOXGUESTCAPSACQUIRE_FLAGS_CONFIG_ACQUIRE_MODE)
+ {
+ RTSpinlockRelease(pDevExt->EventSpinlock);
+
+ Assert(!pReq);
+ Log(("vgdrvAcquireSessionCapabilities: pSession=%p fOrMask=%#x fNotMask=%#x enmFlags=%#x: configured acquire caps: 0x%x\n",
+ pSession, fOrMask, fNotMask, enmFlags));
+ return VINF_SUCCESS;
+ }
+ Assert(pReq || fSessionTermination);
+
+ /*
+ * Caller wants to acquire/release the capabilities too.
+ *
+ * Note! The mode change of the capabilities above won't be reverted on
+ * failure, this is intentional.
+ */
+ fCurrentOwnedCaps = pSession->fAcquiredGuestCaps;
+ fSessionRemovedCaps = fCurrentOwnedCaps & fNotMask;
+ fSessionAddedCaps = fOrMask & ~fCurrentOwnedCaps;
+ fOtherConflictingCaps = pDevExt->fAcquiredGuestCaps & ~fCurrentOwnedCaps;
+ fOtherConflictingCaps &= fSessionAddedCaps;
+
+ if (!fOtherConflictingCaps)
+ {
+ if (fSessionAddedCaps)
+ {
+ pSession->fAcquiredGuestCaps |= fSessionAddedCaps;
+ pDevExt->fAcquiredGuestCaps |= fSessionAddedCaps;
+ }
+
+ if (fSessionRemovedCaps)
+ {
+ pSession->fAcquiredGuestCaps &= ~fSessionRemovedCaps;
+ pDevExt->fAcquiredGuestCaps &= ~fSessionRemovedCaps;
+ }
+
+ /*
+ * If something changes (which is very likely), tell the host.
+ */
+ if (fSessionAddedCaps || fSessionRemovedCaps || pDevExt->fGuestCapsHost == UINT32_MAX)
+ {
+ Assert(pReq || fSessionTermination);
+ if (pReq)
+ {
+ rc = vgdrvUpdateCapabilitiesOnHostWithReqAndLock(pDevExt, pReq);
+ if (RT_FAILURE(rc) && !fSessionTermination)
+ {
+ /* Failed, roll back. */
+ if (fSessionAddedCaps)
+ {
+ pSession->fAcquiredGuestCaps &= ~fSessionAddedCaps;
+ pDevExt->fAcquiredGuestCaps &= ~fSessionAddedCaps;
+ }
+ if (fSessionRemovedCaps)
+ {
+ pSession->fAcquiredGuestCaps |= fSessionRemovedCaps;
+ pDevExt->fAcquiredGuestCaps |= fSessionRemovedCaps;
+ }
+
+ RTSpinlockRelease(pDevExt->EventSpinlock);
+ LogRel(("vgdrvAcquireSessionCapabilities: vgdrvUpdateCapabilitiesOnHostWithReqAndLock failed: rc=%Rrc\n", rc));
+ VbglGRFree(&pReq->header);
+ return rc;
+ }
+ }
+ }
+ }
+ else
+ {
+ RTSpinlockRelease(pDevExt->EventSpinlock);
+
+ Log(("vgdrvAcquireSessionCapabilities: Caps %#x were busy\n", fOtherConflictingCaps));
+ VbglGRFree(&pReq->header);
+ return VERR_RESOURCE_BUSY;
+ }
+
+ RTSpinlockRelease(pDevExt->EventSpinlock);
+ if (pReq)
+ VbglGRFree(&pReq->header);
+
+ /*
+ * If we added a capability, check if that means some other thread in our
+ * session should be unblocked because there are events pending.
+ *
+ * HACK ALERT! When the seamless support capability is added we generate a
+ * seamless change event so that the ring-3 client can sync with
+ * the seamless state. Although this introduces a spurious
+ * wakeups of the ring-3 client, it solves the problem of client
+ * state inconsistency in multiuser environment (on Windows).
+ */
+ if (fSessionAddedCaps)
+ {
+ uint32_t fGenFakeEvents = 0;
+ if (fSessionAddedCaps & VMMDEV_GUEST_SUPPORTS_SEAMLESS)
+ fGenFakeEvents |= VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST;
+
+ RTSpinlockAcquire(pDevExt->EventSpinlock);
+ if (fGenFakeEvents || pDevExt->f32PendingEvents)
+ vgdrvDispatchEventsLocked(pDevExt, fGenFakeEvents);
+ RTSpinlockRelease(pDevExt->EventSpinlock);
+
+#ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
+ VGDrvCommonWaitDoWakeUps(pDevExt);
+#endif
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Handle VBOXGUEST_IOCTL_GUEST_CAPS_ACQUIRE.
+ *
+ * @returns VBox status code.
+ *
+ * @param pDevExt The device extension.
+ * @param pSession The session.
+ * @param pAcquire The request.
+ */
+static int vgdrvIoCtl_GuestCapsAcquire(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, VBoxGuestCapsAquire *pAcquire)
+{
+ int rc;
+ LogFlow(("VBOXGUEST_IOCTL_GUEST_CAPS_ACQUIRE: or=%#x not=%#x flags=%#x\n",
+ pAcquire->u32OrMask, pAcquire->u32NotMask, pAcquire->enmFlags));
+
+ rc = vgdrvAcquireSessionCapabilities(pDevExt, pSession, pAcquire->u32OrMask, pAcquire->u32NotMask, pAcquire->enmFlags,
+ false /*fSessionTermination*/);
+ if (RT_FAILURE(rc))
+ LogRel(("VGDrvCommonIoCtl: GUEST_CAPS_ACQUIRE failed rc=%Rrc\n", rc));
+ pAcquire->rc = rc;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Sets the guest capabilities for a session.
+ *
+ * @returns VBox status code.
+ * @param pDevExt The device extension.
+ * @param pSession The session.
+ * @param fOrMask The capabilities to add.
+ * @param fNotMask The capabilities to remove.
+ * @param fSessionTermination Set if we're called by the session cleanup code.
+ * This tweaks the error handling so we perform
+ * proper session cleanup even if the host
+ * misbehaves.
+ *
+ * @remarks Takes the session spinlock.
+ */
+static int vgdrvSetSessionCapabilities(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
+ uint32_t fOrMask, uint32_t fNotMask, bool fSessionTermination)
+{
+ /*
+ * Preallocate a request buffer so we can do all in one go without leaving the spinlock.
+ */
+ VMMDevReqGuestCapabilities2 *pReq;
+ int rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_SetGuestCapabilities);
+ if (RT_SUCCESS(rc))
+ { /* nothing */ }
+ else if (!fSessionTermination)
+ {
+ LogRel(("vgdrvSetSessionCapabilities: VbglGRAlloc failure: %Rrc\n", rc));
+ return rc;
+ }
+ else
+ pReq = NULL; /* Ignore failure, we must do session cleanup. */
+
+
+ RTSpinlockAcquire(pDevExt->SessionSpinlock);
+
+#ifndef VBOXGUEST_DISREGARD_ACQUIRE_MODE_GUEST_CAPS
+ /*
+ * Capabilities in "acquire" mode cannot be set via this API.
+ * (Acquire mode is only used on windows at the time of writing.)
+ */
+ if (!(fOrMask & pDevExt->fAcquireModeGuestCaps))
+#endif
+ {
+ /*
+ * Apply the changes to the session mask.
+ */
+ uint32_t fChanged;
+ uint32_t fPrevious = pSession->fCapabilities;
+ pSession->fCapabilities |= fOrMask;
+ pSession->fCapabilities &= ~fNotMask;
+
+ /*
+ * If anything actually changed, update the global usage counters.
+ */
+ fChanged = fPrevious ^ pSession->fCapabilities;
+ if (fChanged)
+ {
+ bool fGlobalChange = vgdrvBitUsageTrackerChange(&pDevExt->SetGuestCapsTracker, fChanged, fPrevious,
+ pDevExt->cSessions, "SetGuestCapsTracker");
+
+ /*
+ * If there are global changes, update the capabilities on the host.
+ */
+ if (fGlobalChange || pDevExt->fGuestCapsHost == UINT32_MAX)
+ {
+ Assert(pReq || fSessionTermination);
+ if (pReq)
+ {
+ rc = vgdrvUpdateCapabilitiesOnHostWithReqAndLock(pDevExt, pReq);
+
+ /* On failure, roll back (unless it's session termination time). */
+ if (RT_FAILURE(rc) && !fSessionTermination)
+ {
+ vgdrvBitUsageTrackerChange(&pDevExt->SetGuestCapsTracker, fChanged, pSession->fCapabilities,
+ pDevExt->cSessions, "SetGuestCapsTracker");
+ pSession->fCapabilities = fPrevious;
+ }
+ }
+ }
+ }
+ }
+#ifndef VBOXGUEST_DISREGARD_ACQUIRE_MODE_GUEST_CAPS
+ else
+ rc = VERR_RESOURCE_BUSY;
+#endif
+
+ RTSpinlockRelease(pDevExt->SessionSpinlock);
+ if (pReq)
+ VbglGRFree(&pReq->header);
+ return rc;
+}
+
+
+/**
+ * Handle VBOXGUEST_IOCTL_SET_GUEST_CAPABILITIES.
+ *
+ * @returns VBox status code.
+ *
+ * @param pDevExt The device extension.
+ * @param pSession The session.
+ * @param pInfo The request.
+ */
+static int vgdrvIoCtl_SetCapabilities(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, VBoxGuestSetCapabilitiesInfo *pInfo)
+{
+ int rc;
+ LogFlow(("VBOXGUEST_IOCTL_SET_GUEST_CAPABILITIES: or=%#x not=%#x\n", pInfo->u32OrMask, pInfo->u32NotMask));
+
+ if (!((pInfo->u32OrMask | pInfo->u32NotMask) & ~VMMDEV_GUEST_CAPABILITIES_MASK))
+ rc = vgdrvSetSessionCapabilities(pDevExt, pSession, pInfo->u32OrMask, pInfo->u32NotMask, false /*fSessionTermination*/);
+ else
+ rc = VERR_INVALID_PARAMETER;
+
+ return rc;
+}
+
+/** @} */
+
+
+/**
+ * Common IOCtl for user to kernel and kernel to kernel communication.
+ *
+ * This function only does the basic validation and then invokes
+ * worker functions that takes care of each specific function.
+ *
+ * @returns VBox status code.
+ *
+ * @param iFunction The requested function.
+ * @param pDevExt The device extension.
+ * @param pSession The client session.
+ * @param pvData The input/output data buffer. Can be NULL depending on the function.
+ * @param cbData The max size of the data buffer.
+ * @param pcbDataReturned Where to store the amount of returned data. Can be NULL.
+ */
+int VGDrvCommonIoCtl(unsigned iFunction, PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
+ void *pvData, size_t cbData, size_t *pcbDataReturned)
+{
+ int rc;
+ LogFlow(("VGDrvCommonIoCtl: iFunction=%#x pDevExt=%p pSession=%p pvData=%p cbData=%zu\n",
+ iFunction, pDevExt, pSession, pvData, cbData));
+
+ /*
+ * Make sure the returned data size is set to zero.
+ */
+ if (pcbDataReturned)
+ *pcbDataReturned = 0;
+
+ /*
+ * Define some helper macros to simplify validation.
+ */
+#define CHECKRET_RING0(mnemonic) \
+ do { \
+ if (pSession->R0Process != NIL_RTR0PROCESS) \
+ { \
+ LogFunc((mnemonic ": Ring-0 only, caller is %RTproc/%p\n", \
+ pSession->Process, (uintptr_t)pSession->R0Process)); \
+ return VERR_PERMISSION_DENIED; \
+ } \
+ } while (0)
+#define CHECKRET_MIN_SIZE(mnemonic, cbMin) \
+ do { \
+ if (cbData < (cbMin)) \
+ { \
+ LogFunc((mnemonic ": cbData=%#zx (%zu) min is %#zx (%zu)\n", \
+ cbData, cbData, (size_t)(cbMin), (size_t)(cbMin))); \
+ return VERR_BUFFER_OVERFLOW; \
+ } \
+ if ((cbMin) != 0 && !VALID_PTR(pvData)) \
+ { \
+ LogFunc((mnemonic ": Invalid pointer %p\n", pvData)); \
+ return VERR_INVALID_POINTER; \
+ } \
+ } while (0)
+#define CHECKRET_SIZE(mnemonic, cb) \
+ do { \
+ if (cbData != (cb)) \
+ { \
+ LogFunc((mnemonic ": cbData=%#zx (%zu) expected is %#zx (%zu)\n", \
+ cbData, cbData, (size_t)(cb), (size_t)(cb))); \
+ return VERR_BUFFER_OVERFLOW; \
+ } \
+ if ((cb) != 0 && !VALID_PTR(pvData)) \
+ { \
+ LogFunc((mnemonic ": Invalid pointer %p\n", pvData)); \
+ return VERR_INVALID_POINTER; \
+ } \
+ } while (0)
+
+
+ /*
+ * Deal with variably sized requests first.
+ */
+ rc = VINF_SUCCESS;
+ if (VBOXGUEST_IOCTL_STRIP_SIZE(iFunction) == VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_VMMREQUEST(0)))
+ {
+ CHECKRET_MIN_SIZE("VMMREQUEST", sizeof(VMMDevRequestHeader));
+ rc = vgdrvIoCtl_VMMRequest(pDevExt, pSession, (VMMDevRequestHeader *)pvData, cbData, pcbDataReturned);
+ }
+#ifdef VBOX_WITH_HGCM
+ /*
+ * These ones are a bit tricky.
+ */
+ else if (VBOXGUEST_IOCTL_STRIP_SIZE(iFunction) == VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL(0)))
+ {
+ bool fInterruptible = pSession->R0Process != NIL_RTR0PROCESS;
+ CHECKRET_MIN_SIZE("HGCM_CALL", sizeof(VBoxGuestHGCMCallInfo));
+ rc = vgdrvIoCtl_HGCMCall(pDevExt, pSession, (VBoxGuestHGCMCallInfo *)pvData, RT_INDEFINITE_WAIT,
+ fInterruptible, false /*f32bit*/, false /* fUserData */,
+ 0, cbData, pcbDataReturned);
+ }
+ else if (VBOXGUEST_IOCTL_STRIP_SIZE(iFunction) == VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL_TIMED(0)))
+ {
+ VBoxGuestHGCMCallInfoTimed *pInfo = (VBoxGuestHGCMCallInfoTimed *)pvData;
+ CHECKRET_MIN_SIZE("HGCM_CALL_TIMED", sizeof(VBoxGuestHGCMCallInfoTimed));
+ rc = vgdrvIoCtl_HGCMCall(pDevExt, pSession, &pInfo->info, pInfo->u32Timeout,
+ !!pInfo->fInterruptible || pSession->R0Process != NIL_RTR0PROCESS,
+ false /*f32bit*/, false /* fUserData */,
+ RT_OFFSETOF(VBoxGuestHGCMCallInfoTimed, info), cbData, pcbDataReturned);
+ }
+ else if (VBOXGUEST_IOCTL_STRIP_SIZE(iFunction) == VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL_USERDATA(0)))
+ {
+ bool fInterruptible = true;
+ CHECKRET_MIN_SIZE("HGCM_CALL", sizeof(VBoxGuestHGCMCallInfo));
+ rc = vgdrvIoCtl_HGCMCall(pDevExt, pSession, (VBoxGuestHGCMCallInfo *)pvData, RT_INDEFINITE_WAIT,
+ fInterruptible, false /*f32bit*/, true /* fUserData */,
+ 0, cbData, pcbDataReturned);
+ }
+# ifdef RT_ARCH_AMD64
+ else if (VBOXGUEST_IOCTL_STRIP_SIZE(iFunction) == VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL_32(0)))
+ {
+ bool fInterruptible = pSession->R0Process != NIL_RTR0PROCESS;
+ CHECKRET_MIN_SIZE("HGCM_CALL", sizeof(VBoxGuestHGCMCallInfo));
+ rc = vgdrvIoCtl_HGCMCall(pDevExt, pSession, (VBoxGuestHGCMCallInfo *)pvData, RT_INDEFINITE_WAIT,
+ fInterruptible, true /*f32bit*/, false /* fUserData */,
+ 0, cbData, pcbDataReturned);
+ }
+ else if (VBOXGUEST_IOCTL_STRIP_SIZE(iFunction) == VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL_TIMED_32(0)))
+ {
+ CHECKRET_MIN_SIZE("HGCM_CALL_TIMED", sizeof(VBoxGuestHGCMCallInfoTimed));
+ VBoxGuestHGCMCallInfoTimed *pInfo = (VBoxGuestHGCMCallInfoTimed *)pvData;
+ rc = vgdrvIoCtl_HGCMCall(pDevExt, pSession, &pInfo->info, pInfo->u32Timeout,
+ !!pInfo->fInterruptible || pSession->R0Process != NIL_RTR0PROCESS,
+ true /*f32bit*/, false /* fUserData */,
+ RT_OFFSETOF(VBoxGuestHGCMCallInfoTimed, info), cbData, pcbDataReturned);
+ }
+# endif
+#endif /* VBOX_WITH_HGCM */
+ else if (VBOXGUEST_IOCTL_STRIP_SIZE(iFunction) == VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_LOG(0)))
+ {
+ CHECKRET_MIN_SIZE("LOG", 1);
+ rc = vgdrvIoCtl_Log(pDevExt, (char *)pvData, cbData, pcbDataReturned, pSession->fUserSession);
+ }
+ else
+ {
+ switch (iFunction)
+ {
+ case VBOXGUEST_IOCTL_GETVMMDEVPORT:
+ CHECKRET_RING0("GETVMMDEVPORT");
+ CHECKRET_MIN_SIZE("GETVMMDEVPORT", sizeof(VBoxGuestPortInfo));
+ rc = vgdrvIoCtl_GetVMMDevPort(pDevExt, (VBoxGuestPortInfo *)pvData, pcbDataReturned);
+ break;
+
+#ifndef RT_OS_WINDOWS /* Windows has its own implementation of this. */
+ case VBOXGUEST_IOCTL_SET_MOUSE_NOTIFY_CALLBACK:
+ CHECKRET_RING0("SET_MOUSE_NOTIFY_CALLBACK");
+ CHECKRET_SIZE("SET_MOUSE_NOTIFY_CALLBACK", sizeof(VBoxGuestMouseSetNotifyCallback));
+ rc = vgdrvIoCtl_SetMouseNotifyCallback(pDevExt, (VBoxGuestMouseSetNotifyCallback *)pvData);
+ break;
+#endif
+
+ case VBOXGUEST_IOCTL_WAITEVENT:
+ CHECKRET_MIN_SIZE("WAITEVENT", sizeof(VBoxGuestWaitEventInfo));
+ rc = vgdrvIoCtl_WaitEvent(pDevExt, pSession, (VBoxGuestWaitEventInfo *)pvData,
+ pcbDataReturned, pSession->R0Process != NIL_RTR0PROCESS);
+ break;
+
+ case VBOXGUEST_IOCTL_CANCEL_ALL_WAITEVENTS:
+ CHECKRET_SIZE("CANCEL_ALL_WAITEVENTS", 0);
+ rc = vgdrvIoCtl_CancelAllWaitEvents(pDevExt, pSession);
+ break;
+
+ case VBOXGUEST_IOCTL_CTL_FILTER_MASK:
+ CHECKRET_MIN_SIZE("CTL_FILTER_MASK", sizeof(VBoxGuestFilterMaskInfo));
+ rc = vgdrvIoCtl_CtlFilterMask(pDevExt, pSession, (VBoxGuestFilterMaskInfo *)pvData);
+ break;
+
+#ifdef VBOX_WITH_HGCM
+ case VBOXGUEST_IOCTL_HGCM_CONNECT:
+# ifdef RT_ARCH_AMD64
+ case VBOXGUEST_IOCTL_HGCM_CONNECT_32:
+# endif
+ CHECKRET_MIN_SIZE("HGCM_CONNECT", sizeof(VBoxGuestHGCMConnectInfo));
+ rc = vgdrvIoCtl_HGCMConnect(pDevExt, pSession, (VBoxGuestHGCMConnectInfo *)pvData, pcbDataReturned);
+ break;
+
+ case VBOXGUEST_IOCTL_HGCM_DISCONNECT:
+# ifdef RT_ARCH_AMD64
+ case VBOXGUEST_IOCTL_HGCM_DISCONNECT_32:
+# endif
+ CHECKRET_MIN_SIZE("HGCM_DISCONNECT", sizeof(VBoxGuestHGCMDisconnectInfo));
+ rc = vgdrvIoCtl_HGCMDisconnect(pDevExt, pSession, (VBoxGuestHGCMDisconnectInfo *)pvData, pcbDataReturned);
+ break;
+#endif /* VBOX_WITH_HGCM */
+
+ case VBOXGUEST_IOCTL_CHECK_BALLOON:
+ CHECKRET_MIN_SIZE("CHECK_MEMORY_BALLOON", sizeof(VBoxGuestCheckBalloonInfo));
+ rc = vgdrvIoCtl_CheckMemoryBalloon(pDevExt, pSession, (VBoxGuestCheckBalloonInfo *)pvData, pcbDataReturned);
+ break;
+
+ case VBOXGUEST_IOCTL_CHANGE_BALLOON:
+ CHECKRET_MIN_SIZE("CHANGE_MEMORY_BALLOON", sizeof(VBoxGuestChangeBalloonInfo));
+ rc = vgdrvIoCtl_ChangeMemoryBalloon(pDevExt, pSession, (VBoxGuestChangeBalloonInfo *)pvData, pcbDataReturned);
+ break;
+
+ case VBOXGUEST_IOCTL_WRITE_CORE_DUMP:
+ CHECKRET_MIN_SIZE("WRITE_CORE_DUMP", sizeof(VBoxGuestWriteCoreDump));
+ rc = vgdrvIoCtl_WriteCoreDump(pDevExt, (VBoxGuestWriteCoreDump *)pvData);
+ break;
+
+ case VBOXGUEST_IOCTL_SET_MOUSE_STATUS:
+ CHECKRET_SIZE("SET_MOUSE_STATUS", sizeof(uint32_t));
+ rc = vgdrvIoCtl_SetMouseStatus(pDevExt, pSession, *(uint32_t *)pvData);
+ break;
+
+#ifdef VBOX_WITH_DPC_LATENCY_CHECKER
+ case VBOXGUEST_IOCTL_DPC_LATENCY_CHECKER:
+ CHECKRET_SIZE("DPC_LATENCY_CHECKER", 0);
+ rc = VGDrvNtIOCtl_DpcLatencyChecker();
+ break;
+#endif
+
+ case VBOXGUEST_IOCTL_GUEST_CAPS_ACQUIRE:
+ CHECKRET_SIZE("GUEST_CAPS_ACQUIRE", sizeof(VBoxGuestCapsAquire));
+ rc = vgdrvIoCtl_GuestCapsAcquire(pDevExt, pSession, (VBoxGuestCapsAquire *)pvData);
+ *pcbDataReturned = sizeof(VBoxGuestCapsAquire);
+ break;
+
+ case VBOXGUEST_IOCTL_SET_GUEST_CAPABILITIES:
+ CHECKRET_MIN_SIZE("SET_GUEST_CAPABILITIES", sizeof(VBoxGuestSetCapabilitiesInfo));
+ rc = vgdrvIoCtl_SetCapabilities(pDevExt, pSession, (VBoxGuestSetCapabilitiesInfo *)pvData);
+ break;
+
+ default:
+ {
+ LogRel(("VGDrvCommonIoCtl: Unknown request iFunction=%#x stripped size=%#x\n",
+ iFunction, VBOXGUEST_IOCTL_STRIP_SIZE(iFunction)));
+ rc = VERR_NOT_SUPPORTED;
+ break;
+ }
+ }
+ }
+
+ LogFlow(("VGDrvCommonIoCtl: returns %Rrc *pcbDataReturned=%zu\n", rc, pcbDataReturned ? *pcbDataReturned : 0));
+ return rc;
+}
+
+
+/**
+ * Used by VGDrvCommonISR as well as the acquire guest capability code.
+ *
+ * @returns VINF_SUCCESS on success. On failure, ORed together
+ * RTSemEventMultiSignal errors (completes processing despite errors).
+ * @param pDevExt The VBoxGuest device extension.
+ * @param fEvents The events to dispatch.
+ */
+static int vgdrvDispatchEventsLocked(PVBOXGUESTDEVEXT pDevExt, uint32_t fEvents)
+{
+ PVBOXGUESTWAIT pWait;
+ PVBOXGUESTWAIT pSafe;
+ int rc = VINF_SUCCESS;
+
+ fEvents |= pDevExt->f32PendingEvents;
+
+ RTListForEachSafe(&pDevExt->WaitList, pWait, pSafe, VBOXGUESTWAIT, ListNode)
+ {
+ uint32_t fHandledEvents = pWait->fReqEvents & fEvents;
+ if ( fHandledEvents != 0
+ && !pWait->fResEvents)
+ {
+ /* Does this one wait on any of the events we're dispatching? We do a quick
+ check first, then deal with VBOXGUEST_ACQUIRE_STYLE_EVENTS as applicable. */
+ if (fHandledEvents & VBOXGUEST_ACQUIRE_STYLE_EVENTS)
+ fHandledEvents &= vgdrvGetAllowedEventMaskForSession(pDevExt, pWait->pSession);
+ if (fHandledEvents)
+ {
+ pWait->fResEvents = pWait->fReqEvents & fEvents & fHandledEvents;
+ fEvents &= ~pWait->fResEvents;
+ RTListNodeRemove(&pWait->ListNode);
+#ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
+ RTListAppend(&pDevExt->WakeUpList, &pWait->ListNode);
+#else
+ RTListAppend(&pDevExt->WokenUpList, &pWait->ListNode);
+ rc |= RTSemEventMultiSignal(pWait->Event);
+#endif
+ if (!fEvents)
+ break;
+ }
+ }
+ }
+
+ ASMAtomicWriteU32(&pDevExt->f32PendingEvents, fEvents);
+ return rc;
+}
+
+
+/**
+ * Simply checks whether the IRQ is ours or not, does not do any interrupt
+ * procesing.
+ *
+ * @returns true if it was our interrupt, false if it wasn't.
+ * @param pDevExt The VBoxGuest device extension.
+ */
+bool VGDrvCommonIsOurIRQ(PVBOXGUESTDEVEXT pDevExt)
+{
+ RTSpinlockAcquire(pDevExt->EventSpinlock);
+ bool const fOurIrq = pDevExt->pVMMDevMemory->V.V1_04.fHaveEvents;
+ RTSpinlockRelease(pDevExt->EventSpinlock);
+
+ return fOurIrq;
+}
+
+
+/**
+ * Common interrupt service routine.
+ *
+ * This deals with events and with waking up thread waiting for those events.
+ *
+ * @returns true if it was our interrupt, false if it wasn't.
+ * @param pDevExt The VBoxGuest device extension.
+ */
+bool VGDrvCommonISR(PVBOXGUESTDEVEXT pDevExt)
+{
+ VMMDevEvents volatile *pReq = pDevExt->pIrqAckEvents;
+ bool fMousePositionChanged = false;
+ int rc = 0;
+ bool fOurIrq;
+
+ /*
+ * Make sure we've initialized the device extension.
+ */
+ if (RT_UNLIKELY(!pReq))
+ return false;
+
+ /*
+ * Enter the spinlock and check if it's our IRQ or not.
+ */
+ RTSpinlockAcquire(pDevExt->EventSpinlock);
+ fOurIrq = pDevExt->pVMMDevMemory->V.V1_04.fHaveEvents;
+ if (fOurIrq)
+ {
+ /*
+ * Acknowlegde events.
+ * We don't use VbglGRPerform here as it may take another spinlocks.
+ */
+ pReq->header.rc = VERR_INTERNAL_ERROR;
+ pReq->events = 0;
+ ASMCompilerBarrier();
+ ASMOutU32(pDevExt->IOPortBase + VMMDEV_PORT_OFF_REQUEST, (uint32_t)pDevExt->PhysIrqAckEvents);
+ ASMCompilerBarrier(); /* paranoia */
+ if (RT_SUCCESS(pReq->header.rc))
+ {
+ uint32_t fEvents = pReq->events;
+
+ Log3(("VGDrvCommonISR: acknowledge events succeeded %#RX32\n", fEvents));
+
+ /*
+ * VMMDEV_EVENT_MOUSE_POSITION_CHANGED can only be polled for.
+ */
+ if (fEvents & VMMDEV_EVENT_MOUSE_POSITION_CHANGED)
+ {
+ fMousePositionChanged = true;
+ fEvents &= ~VMMDEV_EVENT_MOUSE_POSITION_CHANGED;
+#if !defined(RT_OS_WINDOWS) && !defined(VBOXGUEST_MOUSE_NOTIFY_CAN_PREEMPT)
+ if (pDevExt->MouseNotifyCallback.pfnNotify)
+ pDevExt->MouseNotifyCallback.pfnNotify(pDevExt->MouseNotifyCallback.pvUser);
+#endif
+ }
+
+#ifdef VBOX_WITH_HGCM
+ /*
+ * The HGCM event/list is kind of different in that we evaluate all entries.
+ */
+ if (fEvents & VMMDEV_EVENT_HGCM)
+ {
+ PVBOXGUESTWAIT pWait;
+ PVBOXGUESTWAIT pSafe;
+ RTListForEachSafe(&pDevExt->HGCMWaitList, pWait, pSafe, VBOXGUESTWAIT, ListNode)
+ {
+ if (pWait->pHGCMReq->fu32Flags & VBOX_HGCM_REQ_DONE)
+ {
+ pWait->fResEvents = VMMDEV_EVENT_HGCM;
+ RTListNodeRemove(&pWait->ListNode);
+# ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
+ RTListAppend(&pDevExt->WakeUpList, &pWait->ListNode);
+# else
+ RTListAppend(&pDevExt->WokenUpList, &pWait->ListNode);
+ rc |= RTSemEventMultiSignal(pWait->Event);
+# endif
+ }
+ }
+ fEvents &= ~VMMDEV_EVENT_HGCM;
+ }
+#endif
+
+ /*
+ * Normal FIFO waiter evaluation.
+ */
+ rc |= vgdrvDispatchEventsLocked(pDevExt, fEvents);
+ }
+ else /* something is serious wrong... */
+ Log(("VGDrvCommonISR: acknowledge events failed rc=%Rrc (events=%#x)!!\n",
+ pReq->header.rc, pReq->events));
+ }
+ else
+ Log3(("VGDrvCommonISR: not ours\n"));
+
+ RTSpinlockRelease(pDevExt->EventSpinlock);
+
+ /*
+ * Execute the mouse notification callback here if it cannot be executed while
+ * holding the interrupt safe spinlock, see @bugref{8639}.
+ */
+#if defined(VBOXGUEST_MOUSE_NOTIFY_CAN_PREEMPT)
+ if ( fMousePositionChanged
+ && pDevExt->MouseNotifyCallback.pfnNotify)
+ pDevExt->MouseNotifyCallback.pfnNotify(pDevExt->MouseNotifyCallback.pvUser);
+#endif
+
+#if defined(VBOXGUEST_USE_DEFERRED_WAKE_UP) && !defined(RT_OS_DARWIN) && !defined(RT_OS_WINDOWS)
+ /*
+ * Do wake-ups.
+ * Note. On Windows this isn't possible at this IRQL, so a DPC will take
+ * care of it. Same on darwin, doing it in the work loop callback.
+ */
+ VGDrvCommonWaitDoWakeUps(pDevExt);
+#endif
+
+ /*
+ * Work the poll and async notification queues on OSes that implements that.
+ * (Do this outside the spinlock to prevent some recursive spinlocking.)
+ */
+ if (fMousePositionChanged)
+ {
+ ASMAtomicIncU32(&pDevExt->u32MousePosChangedSeq);
+ VGDrvNativeISRMousePollEvent(pDevExt);
+ }
+
+ Assert(rc == 0);
+ NOREF(rc);
+ return fOurIrq;
+}
+
--- /dev/null
+/* $Rev: 109079 $ */
+/** @file
+ * VBoxGuest - Inter Driver Communication, unix implementation.
+ *
+ * This file is included by the platform specific source file.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/** @todo Use some header that we have in common with VBoxGuestLib.h... */
+/** @todo fix DECLVBGL usage. */
+RT_C_DECLS_BEGIN
+DECLEXPORT(void *) VBOXCALL VBoxGuestIDCOpen(uint32_t *pu32Version);
+DECLEXPORT(int) VBOXCALL VBoxGuestIDCClose(void *pvSession);
+DECLEXPORT(int) VBOXCALL VBoxGuestIDCCall(void *pvSession, unsigned iCmd, void *pvData, size_t cbData, size_t *pcbDataReturned);
+RT_C_DECLS_END
+
+
+/**
+ * Open a new IDC connection.
+ *
+ * @returns Opaque pointer to session object.
+ * @param pu32Version Where to store VMMDev version.
+ */
+DECLEXPORT(void *) VBOXCALL VBoxGuestIDCOpen(uint32_t *pu32Version)
+{
+ PVBOXGUESTSESSION pSession;
+ int rc;
+ LogFlow(("VBoxGuestIDCOpen: Version=%#x\n", pu32Version ? *pu32Version : 0));
+
+ AssertPtrReturn(pu32Version, NULL);
+
+#ifdef RT_OS_SOLARIS
+ mutex_enter(&g_LdiMtx);
+ if (!g_LdiHandle)
+ {
+ ldi_ident_t DevIdent = ldi_ident_from_anon();
+ rc = ldi_open_by_name(VBOXGUEST_DEVICE_NAME, FREAD, kcred, &g_LdiHandle, DevIdent);
+ ldi_ident_release(DevIdent);
+ if (rc)
+ {
+ LogRel(("VBoxGuestIDCOpen: ldi_open_by_name failed. rc=%d\n", rc));
+ mutex_exit(&g_LdiMtx);
+ return NULL;
+ }
+ }
+ ++g_cLdiOpens;
+ mutex_exit(&g_LdiMtx);
+#endif
+
+ rc = VGDrvCommonCreateKernelSession(&g_DevExt, &pSession);
+ if (RT_SUCCESS(rc))
+ {
+ *pu32Version = VMMDEV_VERSION;
+ return pSession;
+ }
+
+#ifdef RT_OS_SOLARIS
+ mutex_enter(&g_LdiMtx);
+ if (g_cLdiOpens > 0)
+ --g_cLdiOpens;
+ if ( g_cLdiOpens == 0
+ && g_LdiHandle)
+ {
+ ldi_close(g_LdiHandle, FREAD, kcred);
+ g_LdiHandle = NULL;
+ }
+ mutex_exit(&g_LdiMtx);
+#endif
+
+ LogRel(("VBoxGuestIDCOpen: VGDrvCommonCreateKernelSession failed. rc=%d\n", rc));
+ return NULL;
+}
+
+
+/**
+ * Close an IDC connection.
+ *
+ * @returns VBox error code.
+ * @param pvSession Opaque pointer to the session object.
+ */
+DECLEXPORT(int) VBOXCALL VBoxGuestIDCClose(void *pvSession)
+{
+ PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pvSession;
+ LogFlow(("VBoxGuestIDCClose: pvSession=%p\n", pvSession));
+
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ VGDrvCommonCloseSession(&g_DevExt, pSession);
+
+#ifdef RT_OS_SOLARIS
+ mutex_enter(&g_LdiMtx);
+ if (g_cLdiOpens > 0)
+ --g_cLdiOpens;
+ if ( g_cLdiOpens == 0
+ && g_LdiHandle)
+ {
+ ldi_close(g_LdiHandle, FREAD, kcred);
+ g_LdiHandle = NULL;
+ }
+ mutex_exit(&g_LdiMtx);
+#endif
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Perform an IDC call.
+ *
+ * @returns VBox error code.
+ * @param pvSession Opaque pointer to the session.
+ * @param iCmd Requested function.
+ * @param pvData IO data buffer.
+ * @param cbData Size of the data buffer.
+ * @param pcbDataReturned Where to store the amount of returned data.
+ */
+DECLEXPORT(int) VBOXCALL VBoxGuestIDCCall(void *pvSession, unsigned iCmd, void *pvData, size_t cbData, size_t *pcbDataReturned)
+{
+ PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pvSession;
+ LogFlow(("VBoxGuestIDCCall: %pvSession=%p Cmd=%u pvData=%p cbData=%d\n", pvSession, iCmd, pvData, cbData));
+
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertMsgReturn(pSession->pDevExt == &g_DevExt, ("SC: %p != %p\n", pSession->pDevExt, &g_DevExt), VERR_INVALID_HANDLE);
+
+ return VGDrvCommonIoCtl(iCmd, &g_DevExt, pSession, pvData, cbData, pcbDataReturned);
+}
+
--- /dev/null
+/* $Id: VBoxGuestInternal.h $ */
+/** @file
+ * VBoxGuest - Guest Additions Driver, Internal Header.
+ */
+
+/*
+ * Copyright (C) 2010-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___VBoxGuestInternal_h
+#define ___VBoxGuestInternal_h
+
+#include <iprt/types.h>
+#include <iprt/list.h>
+#include <iprt/semaphore.h>
+#include <iprt/spinlock.h>
+#include <iprt/timer.h>
+#include <VBox/VMMDev.h>
+#include <VBox/VBoxGuest.h>
+#include <VBox/VBoxGuestLib.h>
+
+/** @def VBOXGUEST_USE_DEFERRED_WAKE_UP
+ * Defer wake-up of waiting thread when defined. */
+#if defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_WINDOWS) || defined(DOXYGEN_RUNNING)
+# define VBOXGUEST_USE_DEFERRED_WAKE_UP
+#endif
+
+/** @def VBOXGUEST_MOUSE_NOTIFY_CAN_PREEMPT
+ * The mouse notification callback can cause preemption and must not be invoked
+ * while holding a high-level spinlock.
+ */
+#if defined(RT_OS_SOLARIS) || defined(DOXYGEN_RUNNING)
+# define VBOXGUEST_MOUSE_NOTIFY_CAN_PREEMPT
+#endif
+
+/** Pointer to the VBoxGuest per session data. */
+typedef struct VBOXGUESTSESSION *PVBOXGUESTSESSION;
+
+/** Pointer to a wait-for-event entry. */
+typedef struct VBOXGUESTWAIT *PVBOXGUESTWAIT;
+
+/**
+ * VBox guest wait for event entry.
+ *
+ * Each waiting thread allocates one of these items and adds
+ * it to the wait list before going to sleep on the event sem.
+ */
+typedef struct VBOXGUESTWAIT
+{
+ /** The list node. */
+ RTLISTNODE ListNode;
+ /** The events we are waiting on. */
+ uint32_t fReqEvents;
+ /** The events we received. */
+ uint32_t volatile fResEvents;
+#ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
+ /** Set by VGDrvCommonWaitDoWakeUps before leaving the spinlock to call
+ * RTSemEventMultiSignal. */
+ bool volatile fPendingWakeUp;
+ /** Set by the requestor thread if it got the spinlock before the
+ * signaller. Deals with the race in VGDrvCommonWaitDoWakeUps. */
+ bool volatile fFreeMe;
+#endif
+ /** The event semaphore. */
+ RTSEMEVENTMULTI Event;
+ /** The session that's waiting. */
+ PVBOXGUESTSESSION pSession;
+#ifdef VBOX_WITH_HGCM
+ /** The HGCM request we're waiting for to complete. */
+ VMMDevHGCMRequestHeader volatile *pHGCMReq;
+#endif
+} VBOXGUESTWAIT;
+
+
+/**
+ * VBox guest memory balloon.
+ */
+typedef struct VBOXGUESTMEMBALLOON
+{
+ /** Mutex protecting the members below from concurrent access. */
+ RTSEMFASTMUTEX hMtx;
+ /** The current number of chunks in the balloon. */
+ uint32_t cChunks;
+ /** The maximum number of chunks in the balloon (typically the amount of guest
+ * memory / chunksize). */
+ uint32_t cMaxChunks;
+ /** This is true if we are using RTR0MemObjAllocPhysNC() / RTR0MemObjGetPagePhysAddr()
+ * and false otherwise. */
+ bool fUseKernelAPI;
+ /** The current owner of the balloon.
+ * This is automatically assigned to the first session using the ballooning
+ * API and first released when the session closes. */
+ PVBOXGUESTSESSION pOwner;
+ /** The pointer to the array of memory objects holding the chunks of the
+ * balloon. This array is cMaxChunks in size when present. */
+ PRTR0MEMOBJ paMemObj;
+} VBOXGUESTMEMBALLOON;
+/** Pointer to a memory balloon. */
+typedef VBOXGUESTMEMBALLOON *PVBOXGUESTMEMBALLOON;
+
+
+/**
+ * Per bit usage tracker for a uint32_t mask.
+ *
+ * Used for optimal handling of guest properties, mouse status and event filter.
+ */
+typedef struct VBOXGUESTBITUSAGETRACER
+{
+ /** Per bit usage counters. */
+ uint32_t acPerBitUsage[32];
+ /** The current mask according to acPerBitUsage. */
+ uint32_t fMask;
+} VBOXGUESTBITUSAGETRACER;
+/** Pointer to a per bit usage tracker. */
+typedef VBOXGUESTBITUSAGETRACER *PVBOXGUESTBITUSAGETRACER;
+/** Pointer to a const per bit usage tracker. */
+typedef VBOXGUESTBITUSAGETRACER const *PCVBOXGUESTBITUSAGETRACER;
+
+
+/**
+ * VBox guest device (data) extension.
+ */
+typedef struct VBOXGUESTDEVEXT
+{
+ /** The base of the adapter I/O ports. */
+ RTIOPORT IOPortBase;
+ /** Pointer to the mapping of the VMMDev adapter memory. */
+ VMMDevMemory volatile *pVMMDevMemory;
+ /** The memory object reserving space for the guest mappings. */
+ RTR0MEMOBJ hGuestMappings;
+ /** Spinlock protecting the signaling and resetting of the wait-for-event
+ * semaphores as well as the event acking in the ISR. */
+ RTSPINLOCK EventSpinlock;
+ /** Preallocated VMMDevEvents for the IRQ handler. */
+ VMMDevEvents *pIrqAckEvents;
+ /** The physical address of pIrqAckEvents. */
+ RTCCPHYS PhysIrqAckEvents;
+ /** Wait-for-event list for threads waiting for multiple events
+ * (VBOXGUESTWAIT). */
+ RTLISTANCHOR WaitList;
+#ifdef VBOX_WITH_HGCM
+ /** Wait-for-event list for threads waiting on HGCM async completion
+ * (VBOXGUESTWAIT).
+ *
+ * The entire list is evaluated upon the arrival of an HGCM event, unlike
+ * the other lists which are only evaluated till the first thread has
+ * been woken up. */
+ RTLISTANCHOR HGCMWaitList;
+#endif
+#ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
+ /** List of wait-for-event entries that needs waking up
+ * (VBOXGUESTWAIT). */
+ RTLISTANCHOR WakeUpList;
+#endif
+ /** List of wait-for-event entries that has been woken up
+ * (VBOXGUESTWAIT). */
+ RTLISTANCHOR WokenUpList;
+ /** List of free wait-for-event entries (VBOXGUESTWAIT). */
+ RTLISTANCHOR FreeList;
+ /** Mask of pending events. */
+ uint32_t volatile f32PendingEvents;
+ /** Current VMMDEV_EVENT_MOUSE_POSITION_CHANGED sequence number.
+ * Used to implement polling. */
+ uint32_t volatile u32MousePosChangedSeq;
+
+ /** Spinlock various items in the VBOXGUESTSESSION. */
+ RTSPINLOCK SessionSpinlock;
+ /** List of guest sessions (VBOXGUESTSESSION). We currently traverse this
+ * but do not search it, so a list data type should be fine. Use under the
+ * #SessionSpinlock lock. */
+ RTLISTANCHOR SessionList;
+ /** Number of session. */
+ uint32_t cSessions;
+ /** Flag indicating whether logging to the release log
+ * is enabled. */
+ bool fLoggingEnabled;
+ /** Memory balloon information for RTR0MemObjAllocPhysNC(). */
+ VBOXGUESTMEMBALLOON MemBalloon;
+ /** Callback and user data for a kernel mouse handler. */
+ VBoxGuestMouseSetNotifyCallback MouseNotifyCallback;
+
+ /** @name Host Event Filtering
+ * @{ */
+ /** Events we won't permit anyone to filter out. */
+ uint32_t fFixedEvents;
+ /** Usage counters for the host events. (Fixed events are not included.) */
+ VBOXGUESTBITUSAGETRACER EventFilterTracker;
+ /** The event filter last reported to the host (UINT32_MAX on failure). */
+ uint32_t fEventFilterHost;
+ /** @} */
+
+ /** @name Mouse Status
+ * @{ */
+ /** Usage counters for the mouse statuses (VMMDEV_MOUSE_XXX). */
+ VBOXGUESTBITUSAGETRACER MouseStatusTracker;
+ /** The mouse status last reported to the host (UINT32_MAX on failure). */
+ uint32_t fMouseStatusHost;
+ /** @} */
+
+ /** @name Guest Capabilities
+ * @{ */
+ /** Guest capabilities which have been set to "acquire" mode. This means
+ * that only one session can use them at a time, and that they will be
+ * automatically cleaned up if that session exits without doing so.
+ *
+ * Protected by VBOXGUESTDEVEXT::SessionSpinlock, but is unfortunately read
+ * without holding the lock in a couple of places. */
+ uint32_t volatile fAcquireModeGuestCaps;
+ /** Guest capabilities which have been set to "set" mode. This just means
+ * that they have been blocked from ever being set to "acquire" mode. */
+ uint32_t fSetModeGuestCaps;
+ /** Mask of all capabilities which are currently acquired by some session
+ * and as such reported to the host. */
+ uint32_t fAcquiredGuestCaps;
+ /** Usage counters for guest capabilities in "set" mode. Indexed by
+ * capability bit number, one count per session using a capability. */
+ VBOXGUESTBITUSAGETRACER SetGuestCapsTracker;
+ /** The guest capabilities last reported to the host (UINT32_MAX on failure). */
+ uint32_t fGuestCapsHost;
+ /** @} */
+
+ /** Heartbeat timer which fires with interval
+ * cNsHearbeatInterval and its handler sends
+ * VMMDevReq_GuestHeartbeat to VMMDev. */
+ PRTTIMER pHeartbeatTimer;
+ /** Heartbeat timer interval in nanoseconds. */
+ uint64_t cNsHeartbeatInterval;
+ /** Preallocated VMMDevReq_GuestHeartbeat request. */
+ VMMDevRequestHeader *pReqGuestHeartbeat;
+} VBOXGUESTDEVEXT;
+/** Pointer to the VBoxGuest driver data. */
+typedef VBOXGUESTDEVEXT *PVBOXGUESTDEVEXT;
+
+
+/**
+ * The VBoxGuest per session data.
+ */
+typedef struct VBOXGUESTSESSION
+{
+ /** The list node. */
+ RTLISTNODE ListNode;
+#if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) || defined(RT_OS_OS2) || defined(RT_OS_SOLARIS)
+ /** Pointer to the next session with the same hash. */
+ PVBOXGUESTSESSION pNextHash;
+#endif
+#if defined(RT_OS_OS2)
+ /** The system file number of this session. */
+ uint16_t sfn;
+ uint16_t Alignment; /**< Alignment */
+#endif
+ /** The process (id) of the session.
+ * This is NIL if it's a kernel session. */
+ RTPROCESS Process;
+ /** Which process this session is associated with.
+ * This is NIL if it's a kernel session. */
+ RTR0PROCESS R0Process;
+ /** Pointer to the device extension. */
+ PVBOXGUESTDEVEXT pDevExt;
+
+#ifdef VBOX_WITH_HGCM
+ /** Array containing HGCM client IDs associated with this session.
+ * This will be automatically disconnected when the session is closed. */
+ uint32_t volatile aHGCMClientIds[64];
+#endif
+ /** The last consumed VMMDEV_EVENT_MOUSE_POSITION_CHANGED sequence number.
+ * Used to implement polling. */
+ uint32_t volatile u32MousePosChangedSeq;
+ /** Host events requested by the session.
+ * An event type requested in any guest session will be added to the host
+ * filter. Protected by VBOXGUESTDEVEXT::SessionSpinlock. */
+ uint32_t fEventFilter;
+ /** Guest capabilities held in "acquired" by this session.
+ * Protected by VBOXGUESTDEVEXT::SessionSpinlock, but is unfortunately read
+ * without holding the lock in a couple of places. */
+ uint32_t volatile fAcquiredGuestCaps;
+ /** Guest capabilities in "set" mode for this session.
+ * These accumulated for sessions via VBOXGUESTDEVEXT::acGuestCapsSet and
+ * reported to the host. Protected by VBOXGUESTDEVEXT::SessionSpinlock. */
+ uint32_t fCapabilities;
+ /** Mouse features supported. A feature enabled in any guest session will
+ * be enabled for the host.
+ * @note We invert the VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR feature in this
+ * bitmap. The logic of this is that the real feature is when the host
+ * cursor is not needed, and we tell the host it is not needed if any
+ * session explicitly fails to assert it. Storing it inverted simplifies
+ * the checks.
+ * Use under the VBOXGUESTDEVEXT#SessionSpinlock lock. */
+ uint32_t fMouseStatus;
+#ifdef RT_OS_DARWIN
+ /** Pointer to the associated org_virtualbox_VBoxGuestClient object. */
+ void *pvVBoxGuestClient;
+ /** Whether this session has been opened or not. */
+ bool fOpened;
+#endif
+ /** Whether a CANCEL_ALL_WAITEVENTS is pending. This happens when
+ * CANCEL_ALL_WAITEVENTS is called, but no call to WAITEVENT is in process
+ * in the current session. In that case the next call will be interrupted
+ * at once. */
+ bool volatile fPendingCancelWaitEvents;
+ /** Does this session belong to a root process or a user one? */
+ bool fUserSession;
+} VBOXGUESTSESSION;
+
+RT_C_DECLS_BEGIN
+
+int VGDrvCommonInitDevExt(PVBOXGUESTDEVEXT pDevExt, uint16_t IOPortBase, void *pvMMIOBase, uint32_t cbMMIO,
+ VBOXOSTYPE enmOSType, uint32_t fEvents);
+bool VGDrvCommonIsOurIRQ(PVBOXGUESTDEVEXT pDevExt);
+bool VGDrvCommonISR(PVBOXGUESTDEVEXT pDevExt);
+void VGDrvCommonDeleteDevExt(PVBOXGUESTDEVEXT pDevExt);
+int VGDrvCommonReinitDevExtAfterHibernation(PVBOXGUESTDEVEXT pDevExt, VBOXOSTYPE enmOSType);
+#ifdef VBOXGUEST_USE_DEFERRED_WAKE_UP
+void VGDrvCommonWaitDoWakeUps(PVBOXGUESTDEVEXT pDevExt);
+#endif
+
+int VGDrvCommonCreateUserSession(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION *ppSession);
+int VGDrvCommonCreateKernelSession(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION *ppSession);
+void VGDrvCommonCloseSession(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession);
+
+int VGDrvCommonIoCtlFast(unsigned iFunction, PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession);
+int VGDrvCommonIoCtl(unsigned iFunction, PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
+ void *pvData, size_t cbData, size_t *pcbDataReturned);
+
+/**
+ * ISR callback for notifying threads polling for mouse events.
+ *
+ * This is called at the end of the ISR, after leaving the event spinlock, if
+ * VMMDEV_EVENT_MOUSE_POSITION_CHANGED was raised by the host.
+ *
+ * @param pDevExt The device extension.
+ */
+void VGDrvNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt);
+
+
+#ifdef VBOX_WITH_DPC_LATENCY_CHECKER
+int VGDrvNtIOCtl_DpcLatencyChecker(void);
+#endif
+
+#ifdef VBOXGUEST_MOUSE_NOTIFY_CAN_PREEMPT
+int VGDrvNativeSetMouseNotifyCallback(PVBOXGUESTDEVEXT pDevExt, VBoxGuestMouseSetNotifyCallback *pNotify);
+#endif
+
+RT_C_DECLS_END
+
+#endif
+
--- /dev/null
+/* $Id: VBoxGuestLog.h $ */
+/** @file
+ * VBoxGuestLibR0 - Guest Logging facility.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef __VBOXGUESTLOG__H
+#define __VBOXGUESTLOG__H
+
+#ifndef RT_OS_WINDOWS
+# error "Don't include this file."
+#else /* RT_OS_WINDOWS */
+/* Save LOG_ENABLED state, because "VBox/rt/log.h"
+ * may undefine it for IN_RING0 code.
+ */
+# if (defined(DEBUG) && !defined(NO_LOGGING)) || defined(LOG_ENABLED)
+# define __LOG_ENABLED_SAVED__
+# endif
+
+# if (defined(DEBUG) && !defined(NO_LOGGING)) || defined(LOG_ENABLED)
+# ifdef VBOX_GUEST
+# include <VBox/log.h>
+# undef Log
+# define Log(a) RTLogBackdoorPrintf a
+# else
+# define Log(a) DbgPrint a
+# endif
+# else
+# define Log(a)
+# endif
+
+# ifdef __LOG_ENABLED_SAVED__
+# define LOG_ENABLED
+# undef __LOG_ENABLED_SAVED__
+# endif
+
+#endif /* RT_OS_WINDOWS */
+
+#endif /* !__VBOXGUESTLOG__H */
--- /dev/null
+/* $Id: VMMDev.cpp $ */
+/** @file
+ * VBoxGuestLibR0 - VMMDev device related functions.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#include "VBGLInternal.h"
+
+
+DECLVBGL(int) VbglQueryVMMDevMemory(VMMDevMemory **ppVMMDevMemory)
+{
+ int rc = vbglR0Enter();
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* If the memory was not found, return an error. */
+ if (!g_vbgldata.pVMMDevMemory)
+ return VERR_NOT_SUPPORTED;
+
+ *ppVMMDevMemory = g_vbgldata.pVMMDevMemory;
+ return rc;
+}
+
--- /dev/null
+/* $Id: alloc.cpp $ */
+/** @file
+ * IPRT - Memory Allocation.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#ifndef RTMEM_NO_WRAP_TO_EF_APIS
+# define RTMEM_NO_WRAP_TO_EF_APIS
+#endif
+#include <iprt/mem.h>
+#include "internal/iprt.h"
+
+#include <iprt/assert.h>
+#include <iprt/string.h>
+
+
+
+RTDECL(void *) RTMemDupTag(const void *pvSrc, size_t cb, const char *pszTag) RT_NO_THROW_DEF
+{
+ void *pvDst = RTMemAllocTag(cb, pszTag);
+ if (pvDst)
+ memcpy(pvDst, pvSrc, cb);
+ return pvDst;
+}
+RT_EXPORT_SYMBOL(RTMemDupTag);
+
+
+RTDECL(void *) RTMemDupExTag(const void *pvSrc, size_t cbSrc, size_t cbExtra, const char *pszTag) RT_NO_THROW_DEF
+{
+ void *pvDst = RTMemAllocTag(cbSrc + cbExtra, pszTag);
+ if (pvDst)
+ {
+ memcpy(pvDst, pvSrc, cbSrc);
+ memset((uint8_t *)pvDst + cbSrc, 0, cbExtra);
+ }
+ return pvDst;
+}
+RT_EXPORT_SYMBOL(RTMemDupExTag);
+
--- /dev/null
+/* $Id: heapsimple.cpp $ */
+/** @file
+ * IPRT - A Simple Heap.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP RTLOGGROUP_DEFAULT
+#include <iprt/heap.h>
+#include "internal/iprt.h"
+
+#include <iprt/assert.h>
+#include <iprt/asm.h>
+#include <iprt/err.h>
+#include <iprt/log.h>
+#include <iprt/string.h>
+#include <iprt/param.h>
+
+#include "internal/magics.h"
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/** Pointer to the heap anchor block. */
+typedef struct RTHEAPSIMPLEINTERNAL *PRTHEAPSIMPLEINTERNAL;
+/** Pointer to a heap block. */
+typedef struct RTHEAPSIMPLEBLOCK *PRTHEAPSIMPLEBLOCK;
+/** Pointer to a free heap block. */
+typedef struct RTHEAPSIMPLEFREE *PRTHEAPSIMPLEFREE;
+
+/**
+ * Structure describing a simple heap block.
+ * If this block is allocated, it is followed by the user data.
+ * If this block is free, see RTHEAPSIMPLEFREE.
+ */
+typedef struct RTHEAPSIMPLEBLOCK
+{
+ /** The next block in the global block list. */
+ PRTHEAPSIMPLEBLOCK pNext;
+ /** The previous block in the global block list. */
+ PRTHEAPSIMPLEBLOCK pPrev;
+ /** Pointer to the heap anchor block. */
+ PRTHEAPSIMPLEINTERNAL pHeap;
+ /** Flags + magic. */
+ uintptr_t fFlags;
+} RTHEAPSIMPLEBLOCK;
+AssertCompileSizeAlignment(RTHEAPSIMPLEBLOCK, 16);
+
+/** The block is free if this flag is set. When cleared it's allocated. */
+#define RTHEAPSIMPLEBLOCK_FLAGS_FREE ((uintptr_t)RT_BIT(0))
+/** The magic value. */
+#define RTHEAPSIMPLEBLOCK_FLAGS_MAGIC ((uintptr_t)0xabcdef00)
+/** The mask that needs to be applied to RTHEAPSIMPLEBLOCK::fFlags to obtain the magic value. */
+#define RTHEAPSIMPLEBLOCK_FLAGS_MAGIC_MASK (~(uintptr_t)RT_BIT(0))
+
+/**
+ * Checks if the specified block is valid or not.
+ * @returns boolean answer.
+ * @param pBlock Pointer to a RTHEAPSIMPLEBLOCK structure.
+ */
+#define RTHEAPSIMPLEBLOCK_IS_VALID(pBlock) \
+ ( ((pBlock)->fFlags & RTHEAPSIMPLEBLOCK_FLAGS_MAGIC_MASK) == RTHEAPSIMPLEBLOCK_FLAGS_MAGIC )
+
+/**
+ * Checks if the specified block is valid and in use.
+ * @returns boolean answer.
+ * @param pBlock Pointer to a RTHEAPSIMPLEBLOCK structure.
+ */
+#define RTHEAPSIMPLEBLOCK_IS_VALID_USED(pBlock) \
+ ( ((pBlock)->fFlags & (RTHEAPSIMPLEBLOCK_FLAGS_MAGIC_MASK | RTHEAPSIMPLEBLOCK_FLAGS_FREE)) \
+ == RTHEAPSIMPLEBLOCK_FLAGS_MAGIC )
+
+/**
+ * Checks if the specified block is valid and free.
+ * @returns boolean answer.
+ * @param pBlock Pointer to a RTHEAPSIMPLEBLOCK structure.
+ */
+#define RTHEAPSIMPLEBLOCK_IS_VALID_FREE(pBlock) \
+ ( ((pBlock)->fFlags & (RTHEAPSIMPLEBLOCK_FLAGS_MAGIC_MASK | RTHEAPSIMPLEBLOCK_FLAGS_FREE)) \
+ == (RTHEAPSIMPLEBLOCK_FLAGS_MAGIC | RTHEAPSIMPLEBLOCK_FLAGS_FREE) )
+
+/**
+ * Checks if the specified block is free or not.
+ * @returns boolean answer.
+ * @param pBlock Pointer to a valid RTHEAPSIMPLEBLOCK structure.
+ */
+#define RTHEAPSIMPLEBLOCK_IS_FREE(pBlock) (!!((pBlock)->fFlags & RTHEAPSIMPLEBLOCK_FLAGS_FREE))
+
+/**
+ * A free heap block.
+ * This is an extended version of RTHEAPSIMPLEBLOCK that takes the unused
+ * user data to store free list pointers and a cached size value.
+ */
+typedef struct RTHEAPSIMPLEFREE
+{
+ /** Core stuff. */
+ RTHEAPSIMPLEBLOCK Core;
+ /** Pointer to the next free block. */
+ PRTHEAPSIMPLEFREE pNext;
+ /** Pointer to the previous free block. */
+ PRTHEAPSIMPLEFREE pPrev;
+ /** The size of the block (excluding the RTHEAPSIMPLEBLOCK part). */
+ size_t cb;
+ /** An alignment filler to make it a multiple of (sizeof(void *) * 2). */
+ size_t Alignment;
+} RTHEAPSIMPLEFREE;
+
+
+/**
+ * The heap anchor block.
+ * This structure is placed at the head of the memory block specified to RTHeapSimpleInit(),
+ * which means that the first RTHEAPSIMPLEBLOCK appears immediately after this structure.
+ */
+typedef struct RTHEAPSIMPLEINTERNAL
+{
+ /** The typical magic (RTHEAPSIMPLE_MAGIC). */
+ size_t uMagic;
+ /** The heap size. (This structure is included!) */
+ size_t cbHeap;
+ /** Pointer to the end of the heap. */
+ void *pvEnd;
+ /** The amount of free memory in the heap. */
+ size_t cbFree;
+ /** Free head pointer. */
+ PRTHEAPSIMPLEFREE pFreeHead;
+ /** Free tail pointer. */
+ PRTHEAPSIMPLEFREE pFreeTail;
+ /** Make the size of this structure is a multiple of 32. */
+ size_t auAlignment[2];
+} RTHEAPSIMPLEINTERNAL;
+AssertCompileSizeAlignment(RTHEAPSIMPLEINTERNAL, 32);
+
+
+/** The minimum allocation size. */
+#define RTHEAPSIMPLE_MIN_BLOCK (sizeof(RTHEAPSIMPLEBLOCK))
+AssertCompile(RTHEAPSIMPLE_MIN_BLOCK >= sizeof(RTHEAPSIMPLEBLOCK));
+AssertCompile(RTHEAPSIMPLE_MIN_BLOCK >= sizeof(RTHEAPSIMPLEFREE) - sizeof(RTHEAPSIMPLEBLOCK));
+
+/** The minimum and default alignment. */
+#define RTHEAPSIMPLE_ALIGNMENT (sizeof(RTHEAPSIMPLEBLOCK))
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+#ifdef RT_STRICT
+# define RTHEAPSIMPLE_STRICT 1
+#endif
+
+#define ASSERT_L(a, b) AssertMsg((uintptr_t)(a) < (uintptr_t)(b), ("a=%p b=%p\n", (uintptr_t)(a), (uintptr_t)(b)))
+#define ASSERT_LE(a, b) AssertMsg((uintptr_t)(a) <= (uintptr_t)(b), ("a=%p b=%p\n", (uintptr_t)(a), (uintptr_t)(b)))
+#define ASSERT_G(a, b) AssertMsg((uintptr_t)(a) > (uintptr_t)(b), ("a=%p b=%p\n", (uintptr_t)(a), (uintptr_t)(b)))
+#define ASSERT_GE(a, b) AssertMsg((uintptr_t)(a) >= (uintptr_t)(b), ("a=%p b=%p\n", (uintptr_t)(a), (uintptr_t)(b)))
+#define ASSERT_ALIGN(a) AssertMsg(!((uintptr_t)(a) & (RTHEAPSIMPLE_ALIGNMENT - 1)), ("a=%p\n", (uintptr_t)(a)))
+
+#define ASSERT_PREV(pHeapInt, pBlock) \
+ do { ASSERT_ALIGN((pBlock)->pPrev); \
+ if ((pBlock)->pPrev) \
+ { \
+ ASSERT_L((pBlock)->pPrev, (pBlock)); \
+ ASSERT_GE((pBlock)->pPrev, (pHeapInt) + 1); \
+ } \
+ else \
+ Assert((pBlock) == (PRTHEAPSIMPLEBLOCK)((pHeapInt) + 1)); \
+ } while (0)
+
+#define ASSERT_NEXT(pHeap, pBlock) \
+ do { ASSERT_ALIGN((pBlock)->pNext); \
+ if ((pBlock)->pNext) \
+ { \
+ ASSERT_L((pBlock)->pNext, (pHeapInt)->pvEnd); \
+ ASSERT_G((pBlock)->pNext, (pBlock)); \
+ } \
+ } while (0)
+
+#define ASSERT_BLOCK(pHeapInt, pBlock) \
+ do { AssertMsg(RTHEAPSIMPLEBLOCK_IS_VALID(pBlock), ("%#x\n", (pBlock)->fFlags)); \
+ AssertMsg((pBlock)->pHeap == (pHeapInt), ("%p != %p\n", (pBlock)->pHeap, (pHeapInt))); \
+ ASSERT_GE((pBlock), (pHeapInt) + 1); \
+ ASSERT_L((pBlock), (pHeapInt)->pvEnd); \
+ ASSERT_NEXT(pHeapInt, pBlock); \
+ ASSERT_PREV(pHeapInt, pBlock); \
+ } while (0)
+
+#define ASSERT_BLOCK_USED(pHeapInt, pBlock) \
+ do { AssertMsg(RTHEAPSIMPLEBLOCK_IS_VALID_USED((pBlock)), ("%#x\n", (pBlock)->fFlags)); \
+ AssertMsg((pBlock)->pHeap == (pHeapInt), ("%p != %p\n", (pBlock)->pHeap, (pHeapInt))); \
+ ASSERT_GE((pBlock), (pHeapInt) + 1); \
+ ASSERT_L((pBlock), (pHeapInt)->pvEnd); \
+ ASSERT_NEXT(pHeapInt, pBlock); \
+ ASSERT_PREV(pHeapInt, pBlock); \
+ } while (0)
+
+#define ASSERT_FREE_PREV(pHeapInt, pBlock) \
+ do { ASSERT_ALIGN((pBlock)->pPrev); \
+ if ((pBlock)->pPrev) \
+ { \
+ ASSERT_GE((pBlock)->pPrev, (pHeapInt)->pFreeHead); \
+ ASSERT_L((pBlock)->pPrev, (pBlock)); \
+ ASSERT_LE((pBlock)->pPrev, (pBlock)->Core.pPrev); \
+ } \
+ else \
+ Assert((pBlock) == (pHeapInt)->pFreeHead); \
+ } while (0)
+
+#define ASSERT_FREE_NEXT(pHeapInt, pBlock) \
+ do { ASSERT_ALIGN((pBlock)->pNext); \
+ if ((pBlock)->pNext) \
+ { \
+ ASSERT_LE((pBlock)->pNext, (pHeapInt)->pFreeTail); \
+ ASSERT_G((pBlock)->pNext, (pBlock)); \
+ ASSERT_GE((pBlock)->pNext, (pBlock)->Core.pNext); \
+ } \
+ else \
+ Assert((pBlock) == (pHeapInt)->pFreeTail); \
+ } while (0)
+
+#ifdef RTHEAPSIMPLE_STRICT
+# define ASSERT_FREE_CB(pHeapInt, pBlock) \
+ do { size_t cbCalc = ((pBlock)->Core.pNext ? (uintptr_t)(pBlock)->Core.pNext : (uintptr_t)(pHeapInt)->pvEnd) \
+ - (uintptr_t)(pBlock) - sizeof(RTHEAPSIMPLEBLOCK); \
+ AssertMsg((pBlock)->cb == cbCalc, ("cb=%#zx cbCalc=%#zx\n", (pBlock)->cb, cbCalc)); \
+ } while (0)
+#else
+# define ASSERT_FREE_CB(pHeapInt, pBlock) do {} while (0)
+#endif
+
+/** Asserts that a free block is valid. */
+#define ASSERT_BLOCK_FREE(pHeapInt, pBlock) \
+ do { ASSERT_BLOCK(pHeapInt, &(pBlock)->Core); \
+ Assert(RTHEAPSIMPLEBLOCK_IS_VALID_FREE(&(pBlock)->Core)); \
+ ASSERT_GE((pBlock), (pHeapInt)->pFreeHead); \
+ ASSERT_LE((pBlock), (pHeapInt)->pFreeTail); \
+ ASSERT_FREE_NEXT(pHeapInt, pBlock); \
+ ASSERT_FREE_PREV(pHeapInt, pBlock); \
+ ASSERT_FREE_CB(pHeapInt, pBlock); \
+ } while (0)
+
+/** Asserts that the heap anchor block is ok. */
+#define ASSERT_ANCHOR(pHeapInt) \
+ do { AssertPtr(pHeapInt);\
+ Assert((pHeapInt)->uMagic == RTHEAPSIMPLE_MAGIC); \
+ } while (0)
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+#ifdef RTHEAPSIMPLE_STRICT
+static void rtHeapSimpleAssertAll(PRTHEAPSIMPLEINTERNAL pHeapInt);
+#endif
+static PRTHEAPSIMPLEBLOCK rtHeapSimpleAllocBlock(PRTHEAPSIMPLEINTERNAL pHeapInt, size_t cb, size_t uAlignment);
+static void rtHeapSimpleFreeBlock(PRTHEAPSIMPLEINTERNAL pHeapInt, PRTHEAPSIMPLEBLOCK pBlock);
+
+
+RTDECL(int) RTHeapSimpleInit(PRTHEAPSIMPLE phHeap, void *pvMemory, size_t cbMemory)
+{
+ PRTHEAPSIMPLEINTERNAL pHeapInt;
+ PRTHEAPSIMPLEFREE pFree;
+ unsigned i;
+
+ /*
+ * Validate input. The imposed minimum heap size is just a convenient value.
+ */
+ AssertReturn(cbMemory >= PAGE_SIZE, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pvMemory, VERR_INVALID_POINTER);
+ AssertReturn((uintptr_t)pvMemory + (cbMemory - 1) > (uintptr_t)cbMemory, VERR_INVALID_PARAMETER);
+
+ /*
+ * Place the heap anchor block at the start of the heap memory,
+ * enforce 32 byte alignment of it. Also align the heap size correctly.
+ */
+ pHeapInt = (PRTHEAPSIMPLEINTERNAL)pvMemory;
+ if ((uintptr_t)pvMemory & 31)
+ {
+ const uintptr_t off = 32 - ((uintptr_t)pvMemory & 31);
+ cbMemory -= off;
+ pHeapInt = (PRTHEAPSIMPLEINTERNAL)((uintptr_t)pvMemory + off);
+ }
+ cbMemory &= ~(RTHEAPSIMPLE_ALIGNMENT - 1);
+
+
+ /* Init the heap anchor block. */
+ pHeapInt->uMagic = RTHEAPSIMPLE_MAGIC;
+ pHeapInt->pvEnd = (uint8_t *)pHeapInt + cbMemory;
+ pHeapInt->cbHeap = cbMemory;
+ pHeapInt->cbFree = cbMemory
+ - sizeof(RTHEAPSIMPLEBLOCK)
+ - sizeof(RTHEAPSIMPLEINTERNAL);
+ pHeapInt->pFreeTail = pHeapInt->pFreeHead = (PRTHEAPSIMPLEFREE)(pHeapInt + 1);
+ for (i = 0; i < RT_ELEMENTS(pHeapInt->auAlignment); i++)
+ pHeapInt->auAlignment[i] = ~(size_t)0;
+
+ /* Init the single free block. */
+ pFree = pHeapInt->pFreeHead;
+ pFree->Core.pNext = NULL;
+ pFree->Core.pPrev = NULL;
+ pFree->Core.pHeap = pHeapInt;
+ pFree->Core.fFlags = RTHEAPSIMPLEBLOCK_FLAGS_MAGIC | RTHEAPSIMPLEBLOCK_FLAGS_FREE;
+ pFree->pNext = NULL;
+ pFree->pPrev = NULL;
+ pFree->cb = pHeapInt->cbFree;
+
+ *phHeap = pHeapInt;
+
+#ifdef RTHEAPSIMPLE_STRICT
+ rtHeapSimpleAssertAll(pHeapInt);
+#endif
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTHeapSimpleInit);
+
+
+RTDECL(int) RTHeapSimpleRelocate(RTHEAPSIMPLE hHeap, uintptr_t offDelta)
+{
+ PRTHEAPSIMPLEINTERNAL pHeapInt = hHeap;
+ PRTHEAPSIMPLEFREE pCur;
+
+ /*
+ * Validate input.
+ */
+ AssertPtrReturn(pHeapInt, VERR_INVALID_HANDLE);
+ AssertReturn(pHeapInt->uMagic == RTHEAPSIMPLE_MAGIC, VERR_INVALID_HANDLE);
+ AssertMsgReturn((uintptr_t)pHeapInt - (uintptr_t)pHeapInt->pvEnd + pHeapInt->cbHeap == offDelta,
+ ("offDelta=%p, expected=%p\n", offDelta, (uintptr_t)pHeapInt->pvEnd - pHeapInt->cbHeap - (uintptr_t)pHeapInt),
+ VERR_INVALID_PARAMETER);
+
+ /*
+ * Relocate the heap anchor block.
+ */
+#define RELOCATE_IT(var, type, offDelta) do { if (RT_UNLIKELY((var) != NULL)) { (var) = (type)((uintptr_t)(var) + offDelta); } } while (0)
+ RELOCATE_IT(pHeapInt->pvEnd, void *, offDelta);
+ RELOCATE_IT(pHeapInt->pFreeHead, PRTHEAPSIMPLEFREE, offDelta);
+ RELOCATE_IT(pHeapInt->pFreeTail, PRTHEAPSIMPLEFREE, offDelta);
+
+ /*
+ * Walk the heap blocks.
+ */
+ for (pCur = (PRTHEAPSIMPLEFREE)(pHeapInt + 1);
+ pCur && (uintptr_t)pCur < (uintptr_t)pHeapInt->pvEnd;
+ pCur = (PRTHEAPSIMPLEFREE)pCur->Core.pNext)
+ {
+ RELOCATE_IT(pCur->Core.pNext, PRTHEAPSIMPLEBLOCK, offDelta);
+ RELOCATE_IT(pCur->Core.pPrev, PRTHEAPSIMPLEBLOCK, offDelta);
+ RELOCATE_IT(pCur->Core.pHeap, PRTHEAPSIMPLEINTERNAL, offDelta);
+ if (RTHEAPSIMPLEBLOCK_IS_FREE(&pCur->Core))
+ {
+ RELOCATE_IT(pCur->pNext, PRTHEAPSIMPLEFREE, offDelta);
+ RELOCATE_IT(pCur->pPrev, PRTHEAPSIMPLEFREE, offDelta);
+ }
+ }
+#undef RELOCATE_IT
+
+#ifdef RTHEAPSIMPLE_STRICT
+ /*
+ * Give it a once over before we return.
+ */
+ rtHeapSimpleAssertAll(pHeapInt);
+#endif
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTHeapSimpleRelocate);
+
+
+RTDECL(void *) RTHeapSimpleAlloc(RTHEAPSIMPLE hHeap, size_t cb, size_t cbAlignment)
+{
+ PRTHEAPSIMPLEINTERNAL pHeapInt = hHeap;
+ PRTHEAPSIMPLEBLOCK pBlock;
+
+ /*
+ * Validate and adjust the input.
+ */
+ AssertPtrReturn(pHeapInt, NULL);
+ if (cb < RTHEAPSIMPLE_MIN_BLOCK)
+ cb = RTHEAPSIMPLE_MIN_BLOCK;
+ else
+ cb = RT_ALIGN_Z(cb, RTHEAPSIMPLE_ALIGNMENT);
+ if (!cbAlignment)
+ cbAlignment = RTHEAPSIMPLE_ALIGNMENT;
+ else
+ {
+ Assert(!(cbAlignment & (cbAlignment - 1)));
+ Assert((cbAlignment & ~(cbAlignment - 1)) == cbAlignment);
+ if (cbAlignment < RTHEAPSIMPLE_ALIGNMENT)
+ cbAlignment = RTHEAPSIMPLE_ALIGNMENT;
+ }
+
+ /*
+ * Do the allocation.
+ */
+ pBlock = rtHeapSimpleAllocBlock(pHeapInt, cb, cbAlignment);
+ if (RT_LIKELY(pBlock))
+ {
+ void *pv = pBlock + 1;
+ return pv;
+ }
+ return NULL;
+}
+RT_EXPORT_SYMBOL(RTHeapSimpleAlloc);
+
+
+RTDECL(void *) RTHeapSimpleAllocZ(RTHEAPSIMPLE hHeap, size_t cb, size_t cbAlignment)
+{
+ PRTHEAPSIMPLEINTERNAL pHeapInt = hHeap;
+ PRTHEAPSIMPLEBLOCK pBlock;
+
+ /*
+ * Validate and adjust the input.
+ */
+ AssertPtrReturn(pHeapInt, NULL);
+ if (cb < RTHEAPSIMPLE_MIN_BLOCK)
+ cb = RTHEAPSIMPLE_MIN_BLOCK;
+ else
+ cb = RT_ALIGN_Z(cb, RTHEAPSIMPLE_ALIGNMENT);
+ if (!cbAlignment)
+ cbAlignment = RTHEAPSIMPLE_ALIGNMENT;
+ else
+ {
+ Assert(!(cbAlignment & (cbAlignment - 1)));
+ Assert((cbAlignment & ~(cbAlignment - 1)) == cbAlignment);
+ if (cbAlignment < RTHEAPSIMPLE_ALIGNMENT)
+ cbAlignment = RTHEAPSIMPLE_ALIGNMENT;
+ }
+
+ /*
+ * Do the allocation.
+ */
+ pBlock = rtHeapSimpleAllocBlock(pHeapInt, cb, cbAlignment);
+ if (RT_LIKELY(pBlock))
+ {
+ void *pv = pBlock + 1;
+ memset(pv, 0, cb);
+ return pv;
+ }
+ return NULL;
+}
+RT_EXPORT_SYMBOL(RTHeapSimpleAllocZ);
+
+
+/**
+ * Allocates a block of memory from the specified heap.
+ *
+ * No parameter validation or adjustment is performed.
+ *
+ * @returns Pointer to the allocated block.
+ * @returns NULL on failure.
+ *
+ * @param pHeapInt The heap.
+ * @param cb Size of the memory block to allocate.
+ * @param uAlignment The alignment specifications for the allocated block.
+ */
+static PRTHEAPSIMPLEBLOCK rtHeapSimpleAllocBlock(PRTHEAPSIMPLEINTERNAL pHeapInt, size_t cb, size_t uAlignment)
+{
+ PRTHEAPSIMPLEBLOCK pRet = NULL;
+ PRTHEAPSIMPLEFREE pFree;
+
+#ifdef RTHEAPSIMPLE_STRICT
+ rtHeapSimpleAssertAll(pHeapInt);
+#endif
+
+ /*
+ * Search for a fitting block from the lower end of the heap.
+ */
+ for (pFree = pHeapInt->pFreeHead;
+ pFree;
+ pFree = pFree->pNext)
+ {
+ uintptr_t offAlign;
+ ASSERT_BLOCK_FREE(pHeapInt, pFree);
+
+ /*
+ * Match for size and alignment.
+ */
+ if (pFree->cb < cb)
+ continue;
+ offAlign = (uintptr_t)(&pFree->Core + 1) & (uAlignment - 1);
+ if (offAlign)
+ {
+ RTHEAPSIMPLEFREE Free;
+ PRTHEAPSIMPLEBLOCK pPrev;
+
+ offAlign = uAlignment - offAlign;
+ if (pFree->cb - offAlign < cb)
+ continue;
+
+ /*
+ * Make a stack copy of the free block header and adjust the pointer.
+ */
+ Free = *pFree;
+ pFree = (PRTHEAPSIMPLEFREE)((uintptr_t)pFree + offAlign);
+
+ /*
+ * Donate offAlign bytes to the node in front of us.
+ * If we're the head node, we'll have to create a fake node. We'll
+ * mark it USED for simplicity.
+ *
+ * (Should this policy of donating memory to the guy in front of us
+ * cause big 'leaks', we could create a new free node if there is room
+ * for that.)
+ */
+ pPrev = Free.Core.pPrev;
+ if (pPrev)
+ {
+ AssertMsg(!RTHEAPSIMPLEBLOCK_IS_FREE(pPrev), ("Impossible!\n"));
+ pPrev->pNext = &pFree->Core;
+ }
+ else
+ {
+ pPrev = (PRTHEAPSIMPLEBLOCK)(pHeapInt + 1);
+ Assert(pPrev == &pFree->Core);
+ pPrev->pPrev = NULL;
+ pPrev->pNext = &pFree->Core;
+ pPrev->pHeap = pHeapInt;
+ pPrev->fFlags = RTHEAPSIMPLEBLOCK_FLAGS_MAGIC;
+ }
+ pHeapInt->cbFree -= offAlign;
+
+ /*
+ * Recreate pFree in the new position and adjust the neighbors.
+ */
+ *pFree = Free;
+
+ /* the core */
+ if (pFree->Core.pNext)
+ pFree->Core.pNext->pPrev = &pFree->Core;
+ pFree->Core.pPrev = pPrev;
+
+ /* the free part */
+ pFree->cb -= offAlign;
+ if (pFree->pNext)
+ pFree->pNext->pPrev = pFree;
+ else
+ pHeapInt->pFreeTail = pFree;
+ if (pFree->pPrev)
+ pFree->pPrev->pNext = pFree;
+ else
+ pHeapInt->pFreeHead = pFree;
+ ASSERT_BLOCK_FREE(pHeapInt, pFree);
+ ASSERT_BLOCK_USED(pHeapInt, pPrev);
+ }
+
+ /*
+ * Split off a new FREE block?
+ */
+ if (pFree->cb >= cb + RT_ALIGN_Z(sizeof(RTHEAPSIMPLEFREE), RTHEAPSIMPLE_ALIGNMENT))
+ {
+ /*
+ * Move the FREE block up to make room for the new USED block.
+ */
+ PRTHEAPSIMPLEFREE pNew = (PRTHEAPSIMPLEFREE)((uintptr_t)&pFree->Core + cb + sizeof(RTHEAPSIMPLEBLOCK));
+
+ pNew->Core.pNext = pFree->Core.pNext;
+ if (pFree->Core.pNext)
+ pFree->Core.pNext->pPrev = &pNew->Core;
+ pNew->Core.pPrev = &pFree->Core;
+ pNew->Core.pHeap = pHeapInt;
+ pNew->Core.fFlags = RTHEAPSIMPLEBLOCK_FLAGS_MAGIC | RTHEAPSIMPLEBLOCK_FLAGS_FREE;
+
+ pNew->pNext = pFree->pNext;
+ if (pNew->pNext)
+ pNew->pNext->pPrev = pNew;
+ else
+ pHeapInt->pFreeTail = pNew;
+ pNew->pPrev = pFree->pPrev;
+ if (pNew->pPrev)
+ pNew->pPrev->pNext = pNew;
+ else
+ pHeapInt->pFreeHead = pNew;
+ pNew->cb = (pNew->Core.pNext ? (uintptr_t)pNew->Core.pNext : (uintptr_t)pHeapInt->pvEnd) \
+ - (uintptr_t)pNew - sizeof(RTHEAPSIMPLEBLOCK);
+ ASSERT_BLOCK_FREE(pHeapInt, pNew);
+
+ /*
+ * Update the old FREE node making it a USED node.
+ */
+ pFree->Core.fFlags &= ~RTHEAPSIMPLEBLOCK_FLAGS_FREE;
+ pFree->Core.pNext = &pNew->Core;
+ pHeapInt->cbFree -= pFree->cb;
+ pHeapInt->cbFree += pNew->cb;
+ pRet = &pFree->Core;
+ ASSERT_BLOCK_USED(pHeapInt, pRet);
+ }
+ else
+ {
+ /*
+ * Link it out of the free list.
+ */
+ if (pFree->pNext)
+ pFree->pNext->pPrev = pFree->pPrev;
+ else
+ pHeapInt->pFreeTail = pFree->pPrev;
+ if (pFree->pPrev)
+ pFree->pPrev->pNext = pFree->pNext;
+ else
+ pHeapInt->pFreeHead = pFree->pNext;
+
+ /*
+ * Convert it to a used block.
+ */
+ pHeapInt->cbFree -= pFree->cb;
+ pFree->Core.fFlags &= ~RTHEAPSIMPLEBLOCK_FLAGS_FREE;
+ pRet = &pFree->Core;
+ ASSERT_BLOCK_USED(pHeapInt, pRet);
+ }
+ break;
+ }
+
+#ifdef RTHEAPSIMPLE_STRICT
+ rtHeapSimpleAssertAll(pHeapInt);
+#endif
+ return pRet;
+}
+
+
+RTDECL(void) RTHeapSimpleFree(RTHEAPSIMPLE hHeap, void *pv)
+{
+ PRTHEAPSIMPLEINTERNAL pHeapInt;
+ PRTHEAPSIMPLEBLOCK pBlock;
+
+ /*
+ * Validate input.
+ */
+ if (!pv)
+ return;
+ AssertPtr(pv);
+ Assert(RT_ALIGN_P(pv, RTHEAPSIMPLE_ALIGNMENT) == pv);
+
+ /*
+ * Get the block and heap. If in strict mode, validate these.
+ */
+ pBlock = (PRTHEAPSIMPLEBLOCK)pv - 1;
+ pHeapInt = pBlock->pHeap;
+ ASSERT_BLOCK_USED(pHeapInt, pBlock);
+ ASSERT_ANCHOR(pHeapInt);
+ Assert(pHeapInt == (PRTHEAPSIMPLEINTERNAL)hHeap || !hHeap); RT_NOREF_PV(hHeap);
+
+#ifdef RTHEAPSIMPLE_FREE_POISON
+ /*
+ * Poison the block.
+ */
+ const size_t cbBlock = (pBlock->pNext ? (uintptr_t)pBlock->pNext : (uintptr_t)pHeapInt->pvEnd)
+ - (uintptr_t)pBlock - sizeof(RTHEAPSIMPLEBLOCK);
+ memset(pBlock + 1, RTHEAPSIMPLE_FREE_POISON, cbBlock);
+#endif
+
+ /*
+ * Call worker which does the actual job.
+ */
+ rtHeapSimpleFreeBlock(pHeapInt, pBlock);
+}
+RT_EXPORT_SYMBOL(RTHeapSimpleFree);
+
+
+/**
+ * Free a memory block.
+ *
+ * @param pHeapInt The heap.
+ * @param pBlock The memory block to free.
+ */
+static void rtHeapSimpleFreeBlock(PRTHEAPSIMPLEINTERNAL pHeapInt, PRTHEAPSIMPLEBLOCK pBlock)
+{
+ PRTHEAPSIMPLEFREE pFree = (PRTHEAPSIMPLEFREE)pBlock;
+ PRTHEAPSIMPLEFREE pLeft;
+ PRTHEAPSIMPLEFREE pRight;
+
+#ifdef RTHEAPSIMPLE_STRICT
+ rtHeapSimpleAssertAll(pHeapInt);
+#endif
+
+ /*
+ * Look for the closest free list blocks by walking the blocks right
+ * of us (both lists are sorted by address).
+ */
+ pLeft = NULL;
+ pRight = NULL;
+ if (pHeapInt->pFreeTail)
+ {
+ pRight = (PRTHEAPSIMPLEFREE)pFree->Core.pNext;
+ while (pRight && !RTHEAPSIMPLEBLOCK_IS_FREE(&pRight->Core))
+ {
+ ASSERT_BLOCK(pHeapInt, &pRight->Core);
+ pRight = (PRTHEAPSIMPLEFREE)pRight->Core.pNext;
+ }
+ if (!pRight)
+ pLeft = pHeapInt->pFreeTail;
+ else
+ {
+ ASSERT_BLOCK_FREE(pHeapInt, pRight);
+ pLeft = pRight->pPrev;
+ }
+ if (pLeft)
+ ASSERT_BLOCK_FREE(pHeapInt, pLeft);
+ }
+ AssertMsgReturnVoid(pLeft != pFree, ("Freed twice! pv=%p (pBlock=%p)\n", pBlock + 1, pBlock));
+ ASSERT_L(pLeft, pFree);
+ Assert(!pRight || (uintptr_t)pRight > (uintptr_t)pFree);
+ Assert(!pLeft || pLeft->pNext == pRight);
+
+ /*
+ * Insert at the head of the free block list?
+ */
+ if (!pLeft)
+ {
+ Assert(pRight == pHeapInt->pFreeHead);
+ pFree->Core.fFlags |= RTHEAPSIMPLEBLOCK_FLAGS_FREE;
+ pFree->pPrev = NULL;
+ pFree->pNext = pRight;
+ if (pRight)
+ pRight->pPrev = pFree;
+ else
+ pHeapInt->pFreeTail = pFree;
+ pHeapInt->pFreeHead = pFree;
+ }
+ else
+ {
+ /*
+ * Can we merge with left hand free block?
+ */
+ if (pLeft->Core.pNext == &pFree->Core)
+ {
+ pLeft->Core.pNext = pFree->Core.pNext;
+ if (pFree->Core.pNext)
+ pFree->Core.pNext->pPrev = &pLeft->Core;
+ pHeapInt->cbFree -= pLeft->cb;
+ pFree = pLeft;
+ }
+ /*
+ * No, just link it into the free list then.
+ */
+ else
+ {
+ pFree->Core.fFlags |= RTHEAPSIMPLEBLOCK_FLAGS_FREE;
+ pFree->pNext = pRight;
+ pFree->pPrev = pLeft;
+ pLeft->pNext = pFree;
+ if (pRight)
+ pRight->pPrev = pFree;
+ else
+ pHeapInt->pFreeTail = pFree;
+ }
+ }
+
+ /*
+ * Can we merge with right hand free block?
+ */
+ if ( pRight
+ && pRight->Core.pPrev == &pFree->Core)
+ {
+ /* core */
+ pFree->Core.pNext = pRight->Core.pNext;
+ if (pRight->Core.pNext)
+ pRight->Core.pNext->pPrev = &pFree->Core;
+
+ /* free */
+ pFree->pNext = pRight->pNext;
+ if (pRight->pNext)
+ pRight->pNext->pPrev = pFree;
+ else
+ pHeapInt->pFreeTail = pFree;
+ pHeapInt->cbFree -= pRight->cb;
+ }
+
+ /*
+ * Calculate the size and update free stats.
+ */
+ pFree->cb = (pFree->Core.pNext ? (uintptr_t)pFree->Core.pNext : (uintptr_t)pHeapInt->pvEnd)
+ - (uintptr_t)pFree - sizeof(RTHEAPSIMPLEBLOCK);
+ pHeapInt->cbFree += pFree->cb;
+ ASSERT_BLOCK_FREE(pHeapInt, pFree);
+
+#ifdef RTHEAPSIMPLE_STRICT
+ rtHeapSimpleAssertAll(pHeapInt);
+#endif
+}
+
+
+#ifdef RTHEAPSIMPLE_STRICT
+/**
+ * Internal consistency check (relying on assertions).
+ * @param pHeapInt
+ */
+static void rtHeapSimpleAssertAll(PRTHEAPSIMPLEINTERNAL pHeapInt)
+{
+ PRTHEAPSIMPLEFREE pPrev = NULL;
+ PRTHEAPSIMPLEFREE pPrevFree = NULL;
+ PRTHEAPSIMPLEFREE pBlock;
+ for (pBlock = (PRTHEAPSIMPLEFREE)(pHeapInt + 1);
+ pBlock;
+ pBlock = (PRTHEAPSIMPLEFREE)pBlock->Core.pNext)
+ {
+ if (RTHEAPSIMPLEBLOCK_IS_FREE(&pBlock->Core))
+ {
+ ASSERT_BLOCK_FREE(pHeapInt, pBlock);
+ Assert(pBlock->pPrev == pPrevFree);
+ Assert(pPrevFree || pHeapInt->pFreeHead == pBlock);
+ pPrevFree = pBlock;
+ }
+ else
+ ASSERT_BLOCK_USED(pHeapInt, &pBlock->Core);
+ Assert(!pPrev || pPrev == (PRTHEAPSIMPLEFREE)pBlock->Core.pPrev);
+ pPrev = pBlock;
+ }
+ Assert(pHeapInt->pFreeTail == pPrevFree);
+}
+#endif
+
+
+RTDECL(size_t) RTHeapSimpleSize(RTHEAPSIMPLE hHeap, void *pv)
+{
+ PRTHEAPSIMPLEINTERNAL pHeapInt;
+ PRTHEAPSIMPLEBLOCK pBlock;
+ size_t cbBlock;
+
+ /*
+ * Validate input.
+ */
+ if (!pv)
+ return 0;
+ AssertPtrReturn(pv, 0);
+ AssertReturn(RT_ALIGN_P(pv, RTHEAPSIMPLE_ALIGNMENT) == pv, 0);
+
+ /*
+ * Get the block and heap. If in strict mode, validate these.
+ */
+ pBlock = (PRTHEAPSIMPLEBLOCK)pv - 1;
+ pHeapInt = pBlock->pHeap;
+ ASSERT_BLOCK_USED(pHeapInt, pBlock);
+ ASSERT_ANCHOR(pHeapInt);
+ Assert(pHeapInt == (PRTHEAPSIMPLEINTERNAL)hHeap || !hHeap); RT_NOREF_PV(hHeap);
+
+ /*
+ * Calculate the block size.
+ */
+ cbBlock = (pBlock->pNext ? (uintptr_t)pBlock->pNext : (uintptr_t)pHeapInt->pvEnd)
+ - (uintptr_t)pBlock- sizeof(RTHEAPSIMPLEBLOCK);
+ return cbBlock;
+}
+RT_EXPORT_SYMBOL(RTHeapSimpleSize);
+
+
+RTDECL(size_t) RTHeapSimpleGetHeapSize(RTHEAPSIMPLE hHeap)
+{
+ PRTHEAPSIMPLEINTERNAL pHeapInt;
+
+ if (hHeap == NIL_RTHEAPSIMPLE)
+ return 0;
+
+ pHeapInt = hHeap;
+ AssertPtrReturn(pHeapInt, 0);
+ ASSERT_ANCHOR(pHeapInt);
+ return pHeapInt->cbHeap;
+}
+RT_EXPORT_SYMBOL(RTHeapSimpleGetHeapSize);
+
+
+RTDECL(size_t) RTHeapSimpleGetFreeSize(RTHEAPSIMPLE hHeap)
+{
+ PRTHEAPSIMPLEINTERNAL pHeapInt;
+
+ if (hHeap == NIL_RTHEAPSIMPLE)
+ return 0;
+
+ pHeapInt = hHeap;
+ AssertPtrReturn(pHeapInt, 0);
+ ASSERT_ANCHOR(pHeapInt);
+ return pHeapInt->cbFree;
+}
+RT_EXPORT_SYMBOL(RTHeapSimpleGetFreeSize);
+
+
+RTDECL(void) RTHeapSimpleDump(RTHEAPSIMPLE hHeap, PFNRTHEAPSIMPLEPRINTF pfnPrintf)
+{
+ PRTHEAPSIMPLEINTERNAL pHeapInt = (PRTHEAPSIMPLEINTERNAL)hHeap;
+ PRTHEAPSIMPLEFREE pBlock;
+
+ pfnPrintf("**** Dumping Heap %p - cbHeap=%zx cbFree=%zx ****\n",
+ hHeap, pHeapInt->cbHeap, pHeapInt->cbFree);
+
+ for (pBlock = (PRTHEAPSIMPLEFREE)(pHeapInt + 1);
+ pBlock;
+ pBlock = (PRTHEAPSIMPLEFREE)pBlock->Core.pNext)
+ {
+ size_t cb = (pBlock->pNext ? (uintptr_t)pBlock->Core.pNext : (uintptr_t)pHeapInt->pvEnd)
+ - (uintptr_t)pBlock - sizeof(RTHEAPSIMPLEBLOCK);
+ if (RTHEAPSIMPLEBLOCK_IS_FREE(&pBlock->Core))
+ pfnPrintf("%p %06x FREE pNext=%p pPrev=%p fFlags=%#x cb=%#06x : cb=%#06x pNext=%p pPrev=%p\n",
+ pBlock, (uintptr_t)pBlock - (uintptr_t)(pHeapInt + 1), pBlock->Core.pNext, pBlock->Core.pPrev, pBlock->Core.fFlags, cb,
+ pBlock->cb, pBlock->pNext, pBlock->pPrev);
+ else
+ pfnPrintf("%p %06x USED pNext=%p pPrev=%p fFlags=%#x cb=%#06x\n",
+ pBlock, (uintptr_t)pBlock - (uintptr_t)(pHeapInt + 1), pBlock->Core.pNext, pBlock->Core.pPrev, pBlock->Core.fFlags, cb);
+ }
+ pfnPrintf("**** Done dumping Heap %p ****\n", hHeap);
+}
+RT_EXPORT_SYMBOL(RTHeapSimpleDump);
+
--- /dev/null
+/* $Id: RTErrConvertFromErrno.cpp $ */
+/** @file
+ * IPRT - Convert errno to iprt status codes.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/err.h>
+#include "internal/iprt.h"
+
+#include <iprt/assert.h>
+#include <iprt/errno.h>
+
+
+RTDECL(int) RTErrConvertFromErrno(unsigned uNativeCode)
+{
+ /* very fast check for no error. */
+ if (uNativeCode == 0)
+ return VINF_SUCCESS;
+
+ /*
+ * Process error codes.
+ *
+ * (Use a switch and not a table since the numbers vary among compilers
+ * and OSes. So we let the compiler switch optimizer handle speed issues.)
+ *
+ * This switch is arranged like the Linux i386 errno.h! This switch is mirrored
+ * by RTErrConvertToErrno.
+ */
+ switch (uNativeCode)
+ { /* Linux number */
+#ifdef EPERM
+ case EPERM: return VERR_ACCESS_DENIED; /* 1 */
+#endif
+#ifdef ENOENT
+ case ENOENT: return VERR_FILE_NOT_FOUND;
+#endif
+#ifdef ESRCH
+ case ESRCH: return VERR_PROCESS_NOT_FOUND;
+#endif
+#ifdef EINTR
+ case EINTR: return VERR_INTERRUPTED;
+#endif
+#ifdef EIO
+ case EIO: return VERR_DEV_IO_ERROR;
+#endif
+#ifdef ENXIO
+ case ENXIO: return VERR_DEV_IO_ERROR; /** @todo fix this duplicate error */
+#endif
+#ifdef E2BIG
+ case E2BIG: return VERR_TOO_MUCH_DATA;
+#endif
+#ifdef ENOEXEC
+ case ENOEXEC: return VERR_BAD_EXE_FORMAT;
+#endif
+#ifdef EBADF
+ case EBADF: return VERR_INVALID_HANDLE;
+#endif
+#ifdef ECHILD
+ case ECHILD: return VERR_PROCESS_NOT_FOUND; /* 10 */ /** @todo fix duplicate error */
+#endif
+#ifdef EAGAIN
+ case EAGAIN: return VERR_TRY_AGAIN;
+#endif
+#ifdef ENOMEM
+ case ENOMEM: return VERR_NO_MEMORY;
+#endif
+#ifdef EACCES
+ case EACCES: return VERR_ACCESS_DENIED; /** @todo fix duplicate error */
+#endif
+#ifdef EFAULT
+ case EFAULT: return VERR_INVALID_POINTER;
+#endif
+#ifdef ENOTBLK
+ //case ENOTBLK: return VERR_;
+#endif
+#ifdef EBUSY
+ case EBUSY: return VERR_RESOURCE_BUSY;
+#endif
+#ifdef EEXIST
+ case EEXIST: return VERR_ALREADY_EXISTS;
+#endif
+#ifdef EXDEV
+ case EXDEV: return VERR_NOT_SAME_DEVICE;
+#endif
+#ifdef ENODEV
+ case ENODEV: return VERR_NOT_SUPPORTED; /** @todo fix duplicate error */
+#endif
+#ifdef ENOTDIR
+ case ENOTDIR: return VERR_PATH_NOT_FOUND; /* 20 */
+#endif
+#ifdef EISDIR
+ case EISDIR: return VERR_IS_A_DIRECTORY;
+#endif
+#ifdef EINVAL
+ case EINVAL: return VERR_INVALID_PARAMETER;
+#endif
+#ifdef ENFILE
+ case ENFILE: return VERR_TOO_MANY_OPEN_FILES; /** @todo fix duplicate error */
+#endif
+#ifdef EMFILE
+ case EMFILE: return VERR_TOO_MANY_OPEN_FILES;
+#endif
+#ifdef ENOTTY
+ case ENOTTY: return VERR_INVALID_FUNCTION;
+#endif
+#ifdef ETXTBSY
+ case ETXTBSY: return VERR_SHARING_VIOLATION;
+#endif
+#ifdef EFBIG
+ case EFBIG: return VERR_FILE_TOO_BIG;
+#endif
+#ifdef ENOSPC
+ case ENOSPC: return VERR_DISK_FULL;
+#endif
+#ifdef ESPIPE
+ case ESPIPE: return VERR_SEEK_ON_DEVICE;
+#endif
+#ifdef EROFS
+ case EROFS: return VERR_WRITE_PROTECT; /* 30 */
+#endif
+#ifdef EMLINK
+ //case EMLINK:
+#endif
+#ifdef EPIPE
+ case EPIPE: return VERR_BROKEN_PIPE;
+#endif
+#ifdef EDOM
+ case EDOM: return VERR_INVALID_PARAMETER; /** @todo fix duplicate error */
+#endif
+#ifdef ERANGE
+ case ERANGE: return VERR_INVALID_PARAMETER; /** @todo fix duplicate error */
+#endif
+#ifdef EDEADLK
+ case EDEADLK: return VERR_DEADLOCK;
+#endif
+#ifdef ENAMETOOLONG
+ case ENAMETOOLONG: return VERR_FILENAME_TOO_LONG;
+#endif
+#ifdef ENOLCK
+ case ENOLCK: return VERR_FILE_LOCK_FAILED;
+#endif
+#ifdef ENOSYS /** @todo map this differently on solaris. */
+ case ENOSYS: return VERR_NOT_SUPPORTED;
+#endif
+#ifdef ENOTEMPTY
+ case ENOTEMPTY: return VERR_DIR_NOT_EMPTY;
+#endif
+#ifdef ELOOP
+ case ELOOP: return VERR_TOO_MANY_SYMLINKS; /* 40 */
+#endif
+ //41??
+#ifdef ENOMSG
+ //case ENOMSG 42 /* No message of desired type */
+#endif
+#ifdef EIDRM
+ //case EIDRM 43 /* Identifier removed */
+#endif
+#ifdef ECHRNG
+ //case ECHRNG 44 /* Channel number out of range */
+#endif
+#ifdef EL2NSYNC
+ //case EL2NSYNC 45 /* Level 2 not synchronized */
+#endif
+#ifdef EL3HLT
+ //case EL3HLT 46 /* Level 3 halted */
+#endif
+#ifdef EL3RST
+ //case EL3RST 47 /* Level 3 reset */
+#endif
+#ifdef ELNRNG
+ //case ELNRNG 48 /* Link number out of range */
+#endif
+#ifdef EUNATCH
+ //case EUNATCH 49 /* Protocol driver not attached */
+#endif
+#ifdef ENOCSI
+ //case ENOCSI 50 /* No CSI structure available */
+#endif
+#ifdef EL2HLT
+ //case EL2HLT 51 /* Level 2 halted */
+#endif
+#ifdef EBADE
+ //case EBADE 52 /* Invalid exchange */
+#endif
+#ifdef EBADR
+ //case EBADR 53 /* Invalid request descriptor */
+#endif
+#ifdef EXFULL
+ //case EXFULL 54 /* Exchange full */
+#endif
+#ifdef ENOANO
+ //case ENOANO 55 /* No anode */
+#endif
+#ifdef EBADRQC
+ //case EBADRQC 56 /* Invalid request code */
+#endif
+#ifdef EBADSLT
+ //case EBADSLT 57 /* Invalid slot */
+#endif
+ //case 58:
+#ifdef EBFONT
+ //case EBFONT 59 /* Bad font file format */
+#endif
+#ifdef ENOSTR
+ //case ENOSTR 60 /* Device not a stream */
+#endif
+#ifdef ENODATA
+ case ENODATA: return VERR_NO_DATA;
+#endif
+#ifdef ETIME
+ //case ETIME 62 /* Timer expired */
+#endif
+#ifdef ENOSR
+ //case ENOSR 63 /* Out of streams resources */
+#endif
+#ifdef ENONET
+ case ENONET: return VERR_NET_NO_NETWORK;
+#endif
+#ifdef ENOPKG
+ //case ENOPKG 65 /* Package not installed */
+#endif
+#ifdef EREMOTE
+ //case EREMOTE 66 /* Object is remote */
+#endif
+#ifdef ENOLINK
+ //case ENOLINK 67 /* Link has been severed */
+#endif
+#ifdef EADV
+ //case EADV 68 /* Advertise error */
+#endif
+#ifdef ESRMNT
+ //case ESRMNT 69 /* Srmount error */
+#endif
+#ifdef ECOMM
+ //case ECOMM 70 /* Communication error on send */
+#endif
+#ifdef EPROTO
+ case EPROTO: return VERR_NET_PROTOCOL_ERROR;
+#endif
+#ifdef EMULTIHOP
+ //case EMULTIHOP 72 /* Multihop attempted */
+#endif
+#ifdef EDOTDOT
+ //case EDOTDOT 73 /* RFS specific error */
+#endif
+#ifdef EBADMSG
+ //case EBADMSG 74 /* Not a data message */
+#endif
+#ifdef EOVERFLOW
+ case EOVERFLOW: return VERR_TOO_MUCH_DATA; /** @todo fix duplicate error */
+#endif
+#ifdef ENOTUNIQ
+ case ENOTUNIQ: return VERR_NET_NOT_UNIQUE_NAME;
+#endif
+#ifdef EBADFD
+ case EBADFD: return VERR_INVALID_HANDLE; /** @todo fix duplicate error? */
+#endif
+#ifdef EREMCHG
+ //case EREMCHG 78 /* Remote address changed */
+#endif
+#ifdef ELIBACC
+ //case ELIBACC 79 /* Can not access a needed shared library */
+#endif
+#ifdef ELIBBAD
+ //case ELIBBAD 80 /* Accessing a corrupted shared library */
+#endif
+#ifdef ELIBSCN
+ //case ELIBSCN 81 /* .lib section in a.out corrupted */
+#endif
+#ifdef ELIBMAX
+ //case ELIBMAX 82 /* Attempting to link in too many shared libraries */
+#endif
+#ifdef ELIBEXEC
+ //case ELIBEXEC 83 /* Cannot exec a shared library directly */
+#endif
+#ifdef EILSEQ
+ case EILSEQ: return VERR_NO_TRANSLATION;
+#endif
+#ifdef ERESTART
+ case ERESTART: return VERR_INTERRUPTED;/** @todo fix duplicate error?*/
+#endif
+#ifdef ESTRPIPE
+ //case ESTRPIPE 86 /* Streams pipe error */
+#endif
+#ifdef EUSERS
+ //case EUSERS 87 /* Too many users */
+#endif
+#ifdef ENOTSOCK
+ case ENOTSOCK: return VERR_NET_NOT_SOCKET;
+#endif
+#ifdef EDESTADDRREQ
+ case EDESTADDRREQ: return VERR_NET_DEST_ADDRESS_REQUIRED;
+#endif
+#ifdef EMSGSIZE
+ case EMSGSIZE: return VERR_NET_MSG_SIZE;
+#endif
+#ifdef EPROTOTYPE
+ case EPROTOTYPE: return VERR_NET_PROTOCOL_TYPE;
+#endif
+#ifdef ENOPROTOOPT
+ case ENOPROTOOPT: return VERR_NET_PROTOCOL_NOT_AVAILABLE;
+#endif
+#ifdef EPROTONOSUPPORT
+ case EPROTONOSUPPORT: return VERR_NET_PROTOCOL_NOT_SUPPORTED;
+#endif
+#ifdef ESOCKTNOSUPPORT
+ case ESOCKTNOSUPPORT: return VERR_NET_SOCKET_TYPE_NOT_SUPPORTED;
+#endif
+#ifdef EOPNOTSUPP /** @todo map this differently on solaris. */
+ case EOPNOTSUPP: return VERR_NET_OPERATION_NOT_SUPPORTED;
+#endif
+#ifdef EPFNOSUPPORT
+ case EPFNOSUPPORT: return VERR_NET_PROTOCOL_FAMILY_NOT_SUPPORTED;
+#endif
+#ifdef EAFNOSUPPORT
+ case EAFNOSUPPORT: return VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED;
+#endif
+#ifdef EADDRINUSE
+ case EADDRINUSE: return VERR_NET_ADDRESS_IN_USE;
+#endif
+#ifdef EADDRNOTAVAIL
+ case EADDRNOTAVAIL: return VERR_NET_ADDRESS_NOT_AVAILABLE;
+#endif
+#ifdef ENETDOWN
+ case ENETDOWN: return VERR_NET_DOWN;
+#endif
+#ifdef ENETUNREACH
+ case ENETUNREACH: return VERR_NET_UNREACHABLE;
+#endif
+#ifdef ENETRESET
+ case ENETRESET: return VERR_NET_CONNECTION_RESET;
+#endif
+#ifdef ECONNABORTED
+ case ECONNABORTED: return VERR_NET_CONNECTION_ABORTED;
+#endif
+#ifdef ECONNRESET
+ case ECONNRESET: return VERR_NET_CONNECTION_RESET_BY_PEER;
+#endif
+#ifdef ENOBUFS
+ case ENOBUFS: return VERR_NET_NO_BUFFER_SPACE;
+#endif
+#ifdef EISCONN
+ case EISCONN: return VERR_NET_ALREADY_CONNECTED;
+#endif
+#ifdef ENOTCONN
+ case ENOTCONN: return VERR_NET_NOT_CONNECTED;
+#endif
+#ifdef ESHUTDOWN
+ case ESHUTDOWN: return VERR_NET_SHUTDOWN;
+#endif
+#ifdef ETOOMANYREFS
+ case ETOOMANYREFS: return VERR_NET_TOO_MANY_REFERENCES;
+#endif
+#ifdef ETIMEDOUT
+ case ETIMEDOUT: return VERR_TIMEOUT;
+#endif
+#ifdef ECONNREFUSED
+ case ECONNREFUSED: return VERR_NET_CONNECTION_REFUSED;
+#endif
+#ifdef EHOSTDOWN
+ case EHOSTDOWN: return VERR_NET_HOST_DOWN;
+#endif
+#ifdef EHOSTUNREACH
+ case EHOSTUNREACH: return VERR_NET_HOST_UNREACHABLE;
+#endif
+#ifdef EALREADY
+ case EALREADY: return VERR_NET_ALREADY_IN_PROGRESS;
+#endif
+#ifdef EINPROGRESS
+ case EINPROGRESS: return VERR_NET_IN_PROGRESS;
+#endif
+#ifdef ESTALE
+ //case ESTALE 116 /* Stale NFS file handle */
+#endif
+#ifdef EUCLEAN
+ //case EUCLEAN 117 /* Structure needs cleaning */
+#endif
+#ifdef ENOTNAM
+ //case ENOTNAM 118 /* Not a XENIX named type file */
+#endif
+#ifdef ENAVAIL
+ //case ENAVAIL 119 /* No XENIX semaphores available */
+#endif
+#ifdef EISNAM
+ //case EISNAM 120 /* Is a named type file */
+#endif
+#ifdef EREMOTEIO
+ //case EREMOTEIO 121 /* Remote I/O error */
+#endif
+#ifdef EDQUOT
+ case EDQUOT: return VERR_DISK_FULL; /** @todo fix duplicate error */
+#endif
+#ifdef ENOMEDIUM
+ case ENOMEDIUM: return VERR_MEDIA_NOT_PRESENT;
+#endif
+#ifdef EMEDIUMTYPE
+ case EMEDIUMTYPE: return VERR_MEDIA_NOT_RECOGNIZED;
+#endif
+#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
+ case EWOULDBLOCK: return VERR_TRY_AGAIN;
+#endif
+
+ /* Non-linux */
+
+#ifdef EPROCLIM
+ case EPROCLIM: return VERR_MAX_PROCS_REACHED;
+#endif
+#ifdef EDOOFUS
+# if EDOOFUS != EINVAL
+ case EDOOFUS: return VERR_INTERNAL_ERROR;
+# endif
+#endif
+#ifdef ENOTSUP
+# ifndef EOPNOTSUPP
+ case ENOTSUP: return VERR_NOT_SUPPORTED;
+# else
+# if ENOTSUP != EOPNOTSUPP
+ case ENOTSUP: return VERR_NOT_SUPPORTED;
+# endif
+# endif
+#endif
+ default:
+ AssertMsgFailed(("Unhandled error code %d\n", uNativeCode));
+ return VERR_UNRESOLVED_ERROR;
+ }
+}
+RT_EXPORT_SYMBOL(RTErrConvertFromErrno);
+
--- /dev/null
+/* $Id: RTErrConvertToErrno.cpp $ */
+/** @file
+ * IPRT - Convert iprt status codes to errno.
+ */
+
+/*
+ * Copyright (C) 2007-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/err.h>
+#include "internal/iprt.h"
+
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/errno.h>
+
+
+RTDECL(int) RTErrConvertToErrno(int iErr)
+{
+ /* very fast check for no error. */
+ if (RT_SUCCESS(iErr))
+ return 0;
+
+ /*
+ * Process error codes.
+ *
+ * (Use a switch and not a table since the numbers vary among compilers
+ * and OSes. So we let the compiler switch optimizer handle speed issues.)
+ *
+ * This switch is arranged like the Linux i386 errno.h! It also mirrors the
+ * conversions performed by RTErrConvertFromErrno with a few extra case since
+ * there are far more IPRT status codes than Unix ones.
+ */
+ switch (iErr)
+ {
+#ifdef EPERM
+ case VERR_ACCESS_DENIED: return EPERM;
+#endif
+#ifdef ENOENT
+ case VERR_FILE_NOT_FOUND: return ENOENT;
+#endif
+#ifdef ESRCH
+ case VERR_PROCESS_NOT_FOUND: return ESRCH;
+#endif
+#ifdef EINTR
+ case VERR_INTERRUPTED: return EINTR;
+#endif
+#ifdef EIO
+ case VERR_DEV_IO_ERROR: return EIO;
+#endif
+#ifdef ENXIO
+ //case VERR_DEV_IO_ERROR: return ENXIO;
+#endif
+#ifdef E2BIG
+ case VERR_TOO_MUCH_DATA: return E2BIG;
+#endif
+#ifdef ENOEXEC
+ case VERR_BAD_EXE_FORMAT: return ENOEXEC;
+#endif
+#ifdef EBADF
+ case VERR_INVALID_HANDLE: return EBADF;
+#endif
+#ifdef ECHILD
+ //case VERR_PROCESS_NOT_FOUND: return ECHILD;
+#endif
+#ifdef EAGAIN
+ case VERR_TRY_AGAIN: return EAGAIN;
+#endif
+#ifdef ENOMEM
+ case VERR_NO_MEMORY: return ENOMEM;
+#endif
+#ifdef EACCES
+ //case VERR_ACCESS_DENIED: return EACCES;
+#endif
+#ifdef EFAULT
+ case VERR_INVALID_POINTER: return EFAULT;
+#endif
+#ifdef ENOTBLK
+ //case ENOTBLK: return VERR_;
+#endif
+#ifdef EBUSY
+ case VERR_RESOURCE_BUSY: return EBUSY;
+#endif
+#ifdef EEXIST
+ case VERR_ALREADY_EXISTS: return EEXIST;
+#endif
+#ifdef EXDEV
+ case VERR_NOT_SAME_DEVICE: return EXDEV;
+#endif
+#ifdef ENODEV
+ //case VERR_NOT_SUPPORTED: return ENODEV;
+#endif
+#ifdef ENOTDIR
+ case VERR_NOT_A_DIRECTORY:
+ case VERR_PATH_NOT_FOUND: return ENOTDIR;
+#endif
+#ifdef EISDIR
+ case VERR_IS_A_DIRECTORY: return EISDIR;
+#endif
+#ifdef EINVAL
+ case VERR_INVALID_PARAMETER: return EINVAL;
+#endif
+#ifdef ENFILE
+ case VERR_TOO_MANY_OPEN_FILES: return ENFILE;
+#endif
+#ifdef EMFILE
+ //case VERR_TOO_MANY_OPEN_FILES: return EMFILE;
+#endif
+#ifdef ENOTTY
+ case VERR_INVALID_FUNCTION: return ENOTTY;
+#endif
+#ifdef ETXTBSY
+ case VERR_SHARING_VIOLATION: return ETXTBSY;
+#endif
+#ifdef EFBIG
+ case VERR_FILE_TOO_BIG: return EFBIG;
+#endif
+#ifdef ENOSPC
+ case VERR_DISK_FULL: return ENOSPC;
+#endif
+#ifdef ESPIPE
+ case VERR_SEEK_ON_DEVICE: return ESPIPE;
+#endif
+#ifdef EROFS
+ case VERR_WRITE_PROTECT: return EROFS;
+#endif
+#ifdef EMLINK
+ //case EMLINK:
+#endif
+#ifdef EPIPE
+ case VERR_BROKEN_PIPE: return EPIPE;
+#endif
+#ifdef EDOM
+ //case VERR_INVALID_PARAMETER: return EDOM;
+#endif
+#ifdef ERANGE
+ //case VERR_INVALID_PARAMETER: return ERANGE;
+#endif
+#ifdef EDEADLK
+ case VERR_DEADLOCK: return EDEADLK;
+#endif
+#ifdef ENAMETOOLONG
+ case VERR_FILENAME_TOO_LONG: return ENAMETOOLONG;
+#endif
+#ifdef ENOLCK
+ case VERR_FILE_LOCK_FAILED: return ENOLCK;
+#endif
+#ifdef ENOSYS
+ case VERR_NOT_IMPLEMENTED:
+ case VERR_NOT_SUPPORTED: return ENOSYS;
+#endif
+#ifdef ENOTEMPTY
+ case VERR_DIR_NOT_EMPTY: return ENOTEMPTY;
+#endif
+#ifdef ELOOP
+ case VERR_TOO_MANY_SYMLINKS: return ELOOP;
+#endif
+ //41??
+#ifdef ENOMSG
+ //case ENOMSG 42 /* No message of desired type */
+#endif
+#ifdef EIDRM
+ //case EIDRM 43 /* Identifier removed */
+#endif
+#ifdef ECHRNG
+ //case ECHRNG 44 /* Channel number out of range */
+#endif
+#ifdef EL2NSYNC
+ //case EL2NSYNC 45 /* Level 2 not synchronized */
+#endif
+#ifdef EL3HLT
+ //case EL3HLT 46 /* Level 3 halted */
+#endif
+#ifdef EL3RST
+ //case EL3RST 47 /* Level 3 reset */
+#endif
+#ifdef ELNRNG
+ //case ELNRNG 48 /* Link number out of range */
+#endif
+#ifdef EUNATCH
+ //case EUNATCH 49 /* Protocol driver not attached */
+#endif
+#ifdef ENOCSI
+ //case ENOCSI 50 /* No CSI structure available */
+#endif
+#ifdef EL2HLT
+ //case EL2HLT 51 /* Level 2 halted */
+#endif
+#ifdef EBADE
+ //case EBADE 52 /* Invalid exchange */
+#endif
+#ifdef EBADR
+ //case EBADR 53 /* Invalid request descriptor */
+#endif
+#ifdef EXFULL
+ //case EXFULL 54 /* Exchange full */
+#endif
+#ifdef ENOANO
+ //case ENOANO 55 /* No anode */
+#endif
+#ifdef EBADRQC
+ //case EBADRQC 56 /* Invalid request code */
+#endif
+#ifdef EBADSLT
+ //case EBADSLT 57 /* Invalid slot */
+#endif
+ //case 58:
+#ifdef EBFONT
+ //case EBFONT 59 /* Bad font file format */
+#endif
+#ifdef ENOSTR
+ //case ENOSTR 60 /* Device not a stream */
+#endif
+#ifdef ENODATA
+ case VERR_NO_DATA: return ENODATA;
+#endif
+#ifdef ETIME
+ //case ETIME 62 /* Timer expired */
+#endif
+#ifdef ENOSR
+ //case ENOSR 63 /* Out of streams resources */
+#endif
+#ifdef ENONET
+ case VERR_NET_NO_NETWORK: return ENONET;
+#endif
+#ifdef ENOPKG
+ //case ENOPKG 65 /* Package not installed */
+#endif
+#ifdef EREMOTE
+ //case EREMOTE 66 /* Object is remote */
+#endif
+#ifdef ENOLINK
+ //case ENOLINK 67 /* Link has been severed */
+#endif
+#ifdef EADV
+ //case EADV 68 /* Advertise error */
+#endif
+#ifdef ESRMNT
+ //case ESRMNT 69 /* Srmount error */
+#endif
+#ifdef ECOMM
+ //case ECOMM 70 /* Communication error on send */
+#endif
+#ifdef EPROTO
+ //case EPROTO 71 /* Protocol error */
+#endif
+#ifdef EMULTIHOP
+ //case EMULTIHOP 72 /* Multihop attempted */
+#endif
+#ifdef EDOTDOT
+ //case EDOTDOT 73 /* RFS specific error */
+#endif
+#ifdef EBADMSG
+ //case EBADMSG 74 /* Not a data message */
+#endif
+#ifdef EOVERFLOW
+ //case VERR_TOO_MUCH_DATA: return EOVERFLOW;
+#endif
+#ifdef ENOTUNIQ
+ case VERR_NET_NOT_UNIQUE_NAME: return ENOTUNIQ;
+#endif
+#ifdef EBADFD
+ //case VERR_INVALID_HANDLE: return EBADFD;
+#endif
+#ifdef EREMCHG
+ //case EREMCHG 78 /* Remote address changed */
+#endif
+#ifdef ELIBACC
+ //case ELIBACC 79 /* Can not access a needed shared library */
+#endif
+#ifdef ELIBBAD
+ //case ELIBBAD 80 /* Accessing a corrupted shared library */
+#endif
+#ifdef ELIBSCN
+ //case ELIBSCN 81 /* .lib section in a.out corrupted */
+#endif
+#ifdef ELIBMAX
+ //case ELIBMAX 82 /* Attempting to link in too many shared libraries */
+#endif
+#ifdef ELIBEXEC
+ //case ELIBEXEC 83 /* Cannot exec a shared library directly */
+#endif
+#ifdef EILSEQ
+ case VERR_NO_TRANSLATION: return EILSEQ;
+#endif
+#ifdef ERESTART
+ //case VERR_INTERRUPTED: return ERESTART;
+#endif
+#ifdef ESTRPIPE
+ //case ESTRPIPE 86 /* Streams pipe error */
+#endif
+#ifdef EUSERS
+ //case EUSERS 87 /* Too many users */
+#endif
+#ifdef ENOTSOCK
+ case VERR_NET_NOT_SOCKET: return ENOTSOCK;
+#endif
+#ifdef EDESTADDRREQ
+ case VERR_NET_DEST_ADDRESS_REQUIRED: return EDESTADDRREQ;
+#endif
+#ifdef EMSGSIZE
+ case VERR_NET_MSG_SIZE: return EMSGSIZE;
+#endif
+#ifdef EPROTOTYPE
+ case VERR_NET_PROTOCOL_TYPE: return EPROTOTYPE;
+#endif
+#ifdef ENOPROTOOPT
+ case VERR_NET_PROTOCOL_NOT_AVAILABLE: return ENOPROTOOPT;
+#endif
+#ifdef EPROTONOSUPPORT
+ case VERR_NET_PROTOCOL_NOT_SUPPORTED: return EPROTONOSUPPORT;
+#endif
+#ifdef ESOCKTNOSUPPORT
+ case VERR_NET_SOCKET_TYPE_NOT_SUPPORTED: return ESOCKTNOSUPPORT;
+#endif
+#ifdef EOPNOTSUPP
+ case VERR_NET_OPERATION_NOT_SUPPORTED: return EOPNOTSUPP;
+#endif
+#ifdef EPFNOSUPPORT
+ case VERR_NET_PROTOCOL_FAMILY_NOT_SUPPORTED: return EPFNOSUPPORT;
+#endif
+#ifdef EAFNOSUPPORT
+ case VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED: return EAFNOSUPPORT;
+#endif
+#ifdef EADDRINUSE
+ case VERR_NET_ADDRESS_IN_USE: return EADDRINUSE;
+#endif
+#ifdef EADDRNOTAVAIL
+ case VERR_NET_ADDRESS_NOT_AVAILABLE: return EADDRNOTAVAIL;
+#endif
+#ifdef ENETDOWN
+ case VERR_NET_DOWN: return ENETDOWN;
+#endif
+#ifdef ENETUNREACH
+ case VERR_NET_UNREACHABLE: return ENETUNREACH;
+#endif
+#ifdef ENETRESET
+ case VERR_NET_CONNECTION_RESET: return ENETRESET;
+#endif
+#ifdef ECONNABORTED
+ case VERR_NET_CONNECTION_ABORTED: return ECONNABORTED;
+#endif
+#ifdef ECONNRESET
+ case VERR_NET_CONNECTION_RESET_BY_PEER: return ECONNRESET;
+#endif
+#ifdef ENOBUFS
+ case VERR_NET_NO_BUFFER_SPACE: return ENOBUFS;
+#endif
+#ifdef EISCONN
+ case VERR_NET_ALREADY_CONNECTED: return EISCONN;
+#endif
+#ifdef ENOTCONN
+ case VERR_NET_NOT_CONNECTED: return ENOTCONN;
+#endif
+#ifdef ESHUTDOWN
+ case VERR_NET_SHUTDOWN: return ESHUTDOWN;
+#endif
+#ifdef ETOOMANYREFS
+ case VERR_NET_TOO_MANY_REFERENCES: return ETOOMANYREFS;
+#endif
+#ifdef ETIMEDOUT
+ case VERR_TIMEOUT: return ETIMEDOUT;
+#endif
+#ifdef ECONNREFUSED
+ case VERR_NET_CONNECTION_REFUSED: return ECONNREFUSED;
+#endif
+#ifdef EHOSTDOWN
+ case VERR_NET_HOST_DOWN: return EHOSTDOWN;
+#endif
+#ifdef EHOSTUNREACH
+ case VERR_NET_HOST_UNREACHABLE: return EHOSTUNREACH;
+#endif
+#ifdef EALREADY
+ case VERR_NET_ALREADY_IN_PROGRESS: return EALREADY;
+#endif
+#ifdef EINPROGRESS
+ case VERR_NET_IN_PROGRESS: return EINPROGRESS;
+#endif
+#ifdef ESTALE
+ //case ESTALE 116 /* Stale NFS file handle */
+#endif
+#ifdef EUCLEAN
+ //case EUCLEAN 117 /* Structure needs cleaning */
+#endif
+#ifdef ENOTNAM
+ //case ENOTNAM 118 /* Not a XENIX named type file */
+#endif
+#ifdef ENAVAIL
+ //case ENAVAIL 119 /* No XENIX semaphores available */
+#endif
+#ifdef EISNAM
+ //case EISNAM 120 /* Is a named type file */
+#endif
+#ifdef EREMOTEIO
+ //case EREMOTEIO 121 /* Remote I/O error */
+#endif
+#ifdef EDQUOT
+ //case VERR_DISK_FULL: return EDQUOT;
+#endif
+#ifdef ENOMEDIUM
+ case VERR_MEDIA_NOT_PRESENT: return ENOMEDIUM;
+#endif
+#ifdef EMEDIUMTYPE
+ case VERR_MEDIA_NOT_RECOGNIZED: return EMEDIUMTYPE;
+#endif
+
+ /* Non-linux */
+
+#ifdef EPROCLIM
+ case VERR_MAX_PROCS_REACHED: return EPROCLIM;
+#endif
+#ifdef EDOOFUS
+ case VERR_INTERNAL_ERROR:
+ case VERR_INTERNAL_ERROR_2:
+ case VERR_INTERNAL_ERROR_3: return EDOOFUS;
+#endif
+
+ default:
+ /* The idea here is that if you hit this, you will have to
+ translate the status code yourself. */
+ AssertMsgFailed(("Unhandled error code %Rrc\n", iErr));
+#ifdef EPROTO
+ return EPROTO;
+#else
+ return EINVAL;
+#endif
+ }
+}
+RT_EXPORT_SYMBOL(RTErrConvertToErrno);
+
--- /dev/null
+/* $Id: log.cpp $ */
+/** @file
+ * Runtime VBox - Logger.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/log.h>
+#include "internal/iprt.h"
+
+#ifndef IN_RC
+# include <iprt/alloc.h>
+# include <iprt/process.h>
+# include <iprt/semaphore.h>
+# include <iprt/thread.h>
+# include <iprt/mp.h>
+#endif
+#ifdef IN_RING3
+# include <iprt/env.h>
+# include <iprt/file.h>
+# include <iprt/lockvalidator.h>
+# include <iprt/path.h>
+#endif
+#include <iprt/time.h>
+#include <iprt/asm.h>
+#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
+# include <iprt/asm-amd64-x86.h>
+#endif
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/param.h>
+
+#include <iprt/stdarg.h>
+#include <iprt/string.h>
+#include <iprt/ctype.h>
+#ifdef IN_RING3
+# include <iprt/alloca.h>
+# include <stdio.h>
+#endif
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/** @def RTLOG_RINGBUF_DEFAULT_SIZE
+ * The default ring buffer size. */
+/** @def RTLOG_RINGBUF_MAX_SIZE
+ * The max ring buffer size. */
+/** @def RTLOG_RINGBUF_MIN_SIZE
+ * The min ring buffer size. */
+#ifdef IN_RING0
+# define RTLOG_RINGBUF_DEFAULT_SIZE _64K
+# define RTLOG_RINGBUF_MAX_SIZE _4M
+# define RTLOG_RINGBUF_MIN_SIZE _1K
+#elif defined(IN_RING3) || defined(DOXYGEN_RUNNING)
+# define RTLOG_RINGBUF_DEFAULT_SIZE _512K
+# define RTLOG_RINGBUF_MAX_SIZE _1G
+# define RTLOG_RINGBUF_MIN_SIZE _4K
+#endif
+/** The start of ring buffer eye catcher (16 bytes). */
+#define RTLOG_RINGBUF_EYE_CATCHER "START RING BUF\0"
+AssertCompile(sizeof(RTLOG_RINGBUF_EYE_CATCHER) == 16);
+/** The end of ring buffer eye catcher (16 bytes). This also ensures that the ring buffer
+ * forms are properly terminated C string (leading zero chars). */
+#define RTLOG_RINGBUF_EYE_CATCHER_END "\0\0\0END RING BUF"
+AssertCompile(sizeof(RTLOG_RINGBUF_EYE_CATCHER_END) == 16);
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * Arguments passed to the output function.
+ */
+typedef struct RTLOGOUTPUTPREFIXEDARGS
+{
+ /** The logger instance. */
+ PRTLOGGER pLogger;
+ /** The flags. (used for prefixing.) */
+ unsigned fFlags;
+ /** The group. (used for prefixing.) */
+ unsigned iGroup;
+} RTLOGOUTPUTPREFIXEDARGS, *PRTLOGOUTPUTPREFIXEDARGS;
+
+#ifndef IN_RC
+
+/**
+ * Internal logger data.
+ *
+ * @remarks Don't make casual changes to this structure.
+ */
+typedef struct RTLOGGERINTERNAL
+{
+ /** The structure revision (RTLOGGERINTERNAL_REV). */
+ uint32_t uRevision;
+ /** The size of the internal logger structure. */
+ uint32_t cbSelf;
+
+ /** Spinning mutex semaphore. Can be NIL. */
+ RTSEMSPINMUTEX hSpinMtx;
+ /** Pointer to the flush function. */
+ PFNRTLOGFLUSH pfnFlush;
+
+ /** Custom prefix callback. */
+ PFNRTLOGPREFIX pfnPrefix;
+ /** Prefix callback argument. */
+ void *pvPrefixUserArg;
+ /** This is set if a prefix is pending. */
+ bool fPendingPrefix;
+ /** Alignment padding. */
+ bool afPadding1[2];
+ /** Set if fully created. Used to avoid confusing in a few functions used to
+ * parse logger settings from environment variables. */
+ bool fCreated;
+
+ /** The max number of groups that there is room for in afGroups and papszGroups.
+ * Used by RTLogCopyGroupAndFlags(). */
+ uint32_t cMaxGroups;
+ /** Pointer to the group name array.
+ * (The data is readonly and provided by the user.) */
+ const char * const *papszGroups;
+
+ /** The number of log entries per group. NULL if
+ * RTLOGFLAGS_RESTRICT_GROUPS is not specified. */
+ uint32_t *pacEntriesPerGroup;
+ /** The max number of entries per group. */
+ uint32_t cMaxEntriesPerGroup;
+
+ /** @name Ring buffer logging
+ * The ring buffer records the last cbRingBuf - 1 of log output. The
+ * other configured log destinations are not touched until someone calls
+ * RTLogFlush(), when the ring buffer content is written to them all.
+ *
+ * The aim here is a fast logging destination, that avoids wasting storage
+ * space saving disk space when dealing with huge log volumes where the
+ * interesting bits usually are found near the end of the log. This is
+ * typically the case for scenarios that crashes or hits assertions.
+ *
+ * RTLogFlush() is called implicitly when hitting an assertion. While on a
+ * crash the most debuggers are able to make calls these days, it's usually
+ * possible to view the ring buffer memory.
+ *
+ * @{ */
+ /** Ring buffer size (including both eye catchers). */
+ uint32_t cbRingBuf;
+ /** Number of bytes passing thru the ring buffer since last RTLogFlush call.
+ * (This is used to avoid writing out the same bytes twice.) */
+ uint64_t volatile cbRingBufUnflushed;
+ /** Ring buffer pointer (points at RTLOG_RINGBUF_EYE_CATCHER). */
+ char *pszRingBuf;
+ /** Current ring buffer position (where to write the next char). */
+ char * volatile pchRingBufCur;
+ /** @} */
+
+# ifdef IN_RING3 /* Note! Must be at the end! */
+ /** @name File logging bits for the logger.
+ * @{ */
+ /** Pointer to the function called when starting logging, and when
+ * ending or starting a new log file as part of history rotation.
+ * This can be NULL. */
+ PFNRTLOGPHASE pfnPhase;
+
+ /** Handle to log file (if open). */
+ RTFILE hFile;
+ /** Log file history settings: maximum amount of data to put in a file. */
+ uint64_t cbHistoryFileMax;
+ /** Log file history settings: current amount of data in a file. */
+ uint64_t cbHistoryFileWritten;
+ /** Log file history settings: maximum time to use a file (in seconds). */
+ uint32_t cSecsHistoryTimeSlot;
+ /** Log file history settings: in what time slot was the file created. */
+ uint32_t uHistoryTimeSlotStart;
+ /** Log file history settings: number of older files to keep.
+ * 0 means no history. */
+ uint32_t cHistory;
+ /** Pointer to filename. */
+ char szFilename[RTPATH_MAX];
+ /** @} */
+# endif /* IN_RING3 */
+} RTLOGGERINTERNAL;
+
+/** The revision of the internal logger structure. */
+# define RTLOGGERINTERNAL_REV UINT32_C(10)
+
+# ifdef IN_RING3
+/** The size of the RTLOGGERINTERNAL structure in ring-0. */
+# define RTLOGGERINTERNAL_R0_SIZE RT_OFFSETOF(RTLOGGERINTERNAL, pfnPhase)
+AssertCompileMemberAlignment(RTLOGGERINTERNAL, hFile, sizeof(void *));
+AssertCompileMemberAlignment(RTLOGGERINTERNAL, cbHistoryFileMax, sizeof(uint64_t));
+# endif
+AssertCompileMemberAlignment(RTLOGGERINTERNAL, cbRingBufUnflushed, sizeof(uint64_t));
+
+#endif /* !IN_RC */
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+#ifndef IN_RC
+static unsigned rtlogGroupFlags(const char *psz);
+#endif
+#ifdef IN_RING0
+static void rtR0LogLoggerExFallback(uint32_t fDestFlags, uint32_t fFlags, PRTLOGGERINTERNAL pInt,
+ const char *pszFormat, va_list va);
+#endif
+#ifdef IN_RING3
+static int rtlogFileOpen(PRTLOGGER pLogger, char *pszErrorMsg, size_t cchErrorMsg);
+static void rtlogRotate(PRTLOGGER pLogger, uint32_t uTimeSlot, bool fFirst);
+#endif
+#ifndef IN_RC
+static void rtLogRingBufFlush(PRTLOGGER pLogger);
+#endif
+static void rtlogFlush(PRTLOGGER pLogger);
+static DECLCALLBACK(size_t) rtLogOutput(void *pv, const char *pachChars, size_t cbChars);
+static DECLCALLBACK(size_t) rtLogOutputPrefixed(void *pv, const char *pachChars, size_t cbChars);
+static void rtlogLoggerExVLocked(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, va_list args);
+#ifndef IN_RC
+static void rtlogLoggerExFLocked(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, ...);
+#endif
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+#ifdef IN_RC
+/** Default logger instance. Make it weak because our RC module loader does not
+ * necessarily resolve this symbol and the compiler _must_ check if this is
+ * the case or not. That doesn't work for Darwin (``incompatible feature used:
+ * .weak_reference (must specify "-dynamic" to be used'') */
+# ifdef RT_OS_DARWIN
+extern "C" DECLIMPORT(RTLOGGERRC) g_Logger;
+# else
+extern "C" DECLWEAK(DECLIMPORT(RTLOGGERRC)) g_Logger;
+# endif
+#else /* !IN_RC */
+/** Default logger instance. */
+static PRTLOGGER g_pLogger;
+#endif /* !IN_RC */
+#ifdef IN_RING3
+/** The RTThreadGetWriteLockCount() change caused by the logger mutex semaphore. */
+static uint32_t volatile g_cLoggerLockCount;
+#endif
+
+#ifdef IN_RING0
+/** Number of per-thread loggers. */
+static int32_t volatile g_cPerThreadLoggers;
+/** Per-thread loggers.
+ * This is just a quick TLS hack suitable for debug logging only.
+ * If we run out of entries, just unload and reload the driver. */
+static struct RTLOGGERPERTHREAD
+{
+ /** The thread. */
+ RTNATIVETHREAD volatile NativeThread;
+ /** The (process / session) key. */
+ uintptr_t volatile uKey;
+ /** The logger instance.*/
+ PRTLOGGER volatile pLogger;
+} g_aPerThreadLoggers[8] =
+{
+ { NIL_RTNATIVETHREAD, 0, 0},
+ { NIL_RTNATIVETHREAD, 0, 0},
+ { NIL_RTNATIVETHREAD, 0, 0},
+ { NIL_RTNATIVETHREAD, 0, 0},
+ { NIL_RTNATIVETHREAD, 0, 0},
+ { NIL_RTNATIVETHREAD, 0, 0},
+ { NIL_RTNATIVETHREAD, 0, 0},
+ { NIL_RTNATIVETHREAD, 0, 0}
+};
+#endif /* IN_RING0 */
+
+/**
+ * Logger flags instructions.
+ */
+static struct
+{
+ const char *pszInstr; /**< The name */
+ size_t cchInstr; /**< The size of the name. */
+ uint32_t fFlag; /**< The flag value. */
+ bool fInverted; /**< Inverse meaning? */
+} const g_aLogFlags[] =
+{
+ { "disabled", sizeof("disabled" ) - 1, RTLOGFLAGS_DISABLED, false },
+ { "enabled", sizeof("enabled" ) - 1, RTLOGFLAGS_DISABLED, true },
+ { "buffered", sizeof("buffered" ) - 1, RTLOGFLAGS_BUFFERED, false },
+ { "unbuffered", sizeof("unbuffered" ) - 1, RTLOGFLAGS_BUFFERED, true },
+ { "usecrlf", sizeof("usecrlf" ) - 1, RTLOGFLAGS_USECRLF, false },
+ { "uself", sizeof("uself" ) - 1, RTLOGFLAGS_USECRLF, true },
+ { "append", sizeof("append" ) - 1, RTLOGFLAGS_APPEND, false },
+ { "overwrite", sizeof("overwrite" ) - 1, RTLOGFLAGS_APPEND, true },
+ { "rel", sizeof("rel" ) - 1, RTLOGFLAGS_REL_TS, false },
+ { "abs", sizeof("abs" ) - 1, RTLOGFLAGS_REL_TS, true },
+ { "dec", sizeof("dec" ) - 1, RTLOGFLAGS_DECIMAL_TS, false },
+ { "hex", sizeof("hex" ) - 1, RTLOGFLAGS_DECIMAL_TS, true },
+ { "writethru", sizeof("writethru" ) - 1, RTLOGFLAGS_WRITE_THROUGH, false },
+ { "writethrough", sizeof("writethrough") - 1, RTLOGFLAGS_WRITE_THROUGH, false },
+ { "flush", sizeof("flush" ) - 1, RTLOGFLAGS_FLUSH, false },
+ { "lockcnts", sizeof("lockcnts" ) - 1, RTLOGFLAGS_PREFIX_LOCK_COUNTS, false },
+ { "cpuid", sizeof("cpuid" ) - 1, RTLOGFLAGS_PREFIX_CPUID, false },
+ { "pid", sizeof("pid" ) - 1, RTLOGFLAGS_PREFIX_PID, false },
+ { "flagno", sizeof("flagno" ) - 1, RTLOGFLAGS_PREFIX_FLAG_NO, false },
+ { "flag", sizeof("flag" ) - 1, RTLOGFLAGS_PREFIX_FLAG, false },
+ { "groupno", sizeof("groupno" ) - 1, RTLOGFLAGS_PREFIX_GROUP_NO, false },
+ { "group", sizeof("group" ) - 1, RTLOGFLAGS_PREFIX_GROUP, false },
+ { "tid", sizeof("tid" ) - 1, RTLOGFLAGS_PREFIX_TID, false },
+ { "thread", sizeof("thread" ) - 1, RTLOGFLAGS_PREFIX_THREAD, false },
+ { "custom", sizeof("custom" ) - 1, RTLOGFLAGS_PREFIX_CUSTOM, false },
+ { "timeprog", sizeof("timeprog" ) - 1, RTLOGFLAGS_PREFIX_TIME_PROG, false },
+ { "time", sizeof("time" ) - 1, RTLOGFLAGS_PREFIX_TIME, false },
+ { "msprog", sizeof("msprog" ) - 1, RTLOGFLAGS_PREFIX_MS_PROG, false },
+ { "tsc", sizeof("tsc" ) - 1, RTLOGFLAGS_PREFIX_TSC, false }, /* before ts! */
+ { "ts", sizeof("ts" ) - 1, RTLOGFLAGS_PREFIX_TS, false },
+ /* We intentionally omit RTLOGFLAGS_RESTRICT_GROUPS. */
+};
+
+/**
+ * Logger destination instructions.
+ */
+static struct
+{
+ const char *pszInstr; /**< The name. */
+ size_t cchInstr; /**< The size of the name. */
+ uint32_t fFlag; /**< The corresponding destination flag. */
+} const g_aLogDst[] =
+{
+ { RT_STR_TUPLE("file"), RTLOGDEST_FILE }, /* Must be 1st! */
+ { RT_STR_TUPLE("dir"), RTLOGDEST_FILE }, /* Must be 2nd! */
+ { RT_STR_TUPLE("history"), 0 }, /* Must be 3rd! */
+ { RT_STR_TUPLE("histsize"), 0 }, /* Must be 4th! */
+ { RT_STR_TUPLE("histtime"), 0 }, /* Must be 5th! */
+ { RT_STR_TUPLE("ringbuf"), RTLOGDEST_RINGBUF }, /* Must be 6th! */
+ { RT_STR_TUPLE("stdout"), RTLOGDEST_STDOUT },
+ { RT_STR_TUPLE("stderr"), RTLOGDEST_STDERR },
+ { RT_STR_TUPLE("debugger"), RTLOGDEST_DEBUGGER },
+ { RT_STR_TUPLE("com"), RTLOGDEST_COM },
+ { RT_STR_TUPLE("user"), RTLOGDEST_USER },
+};
+
+#ifdef IN_RING3
+/** Log rotation backoff table - millisecond sleep intervals.
+ * Important on Windows host, especially for VBoxSVC release logging. Only a
+ * medium term solution, until a proper fix for log file handling is available.
+ * 10 seconds total.
+ */
+static const uint32_t g_acMsLogBackoff[] =
+{ 10, 10, 10, 20, 50, 100, 200, 200, 200, 200, 500, 500, 500, 500, 1000, 1000, 1000, 1000, 1000, 1000, 1000 };
+#endif
+
+
+/**
+ * Locks the logger instance.
+ *
+ * @returns See RTSemSpinMutexRequest().
+ * @param pLogger The logger instance.
+ */
+DECLINLINE(int) rtlogLock(PRTLOGGER pLogger)
+{
+#ifndef IN_RC
+ PRTLOGGERINTERNAL pInt = pLogger->pInt;
+ AssertMsgReturn(pInt->uRevision == RTLOGGERINTERNAL_REV, ("%#x != %#x\n", pInt->uRevision, RTLOGGERINTERNAL_REV),
+ VERR_LOG_REVISION_MISMATCH);
+ AssertMsgReturn(pInt->cbSelf == sizeof(*pInt), ("%#x != %#x\n", pInt->cbSelf, sizeof(*pInt)),
+ VERR_LOG_REVISION_MISMATCH);
+ if (pInt->hSpinMtx != NIL_RTSEMSPINMUTEX)
+ {
+ int rc = RTSemSpinMutexRequest(pInt->hSpinMtx);
+ if (RT_FAILURE(rc))
+ return rc;
+ }
+#else
+ NOREF(pLogger);
+#endif
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Unlocks the logger instance.
+ * @param pLogger The logger instance.
+ */
+DECLINLINE(void) rtlogUnlock(PRTLOGGER pLogger)
+{
+#ifndef IN_RC
+ if (pLogger->pInt->hSpinMtx != NIL_RTSEMSPINMUTEX)
+ RTSemSpinMutexRelease(pLogger->pInt->hSpinMtx);
+#else
+ NOREF(pLogger);
+#endif
+ return;
+}
+
+#ifndef IN_RC
+# ifdef IN_RING3
+
+# ifdef SOME_UNUSED_FUNCTION
+/**
+ * Logging to file, output callback.
+ *
+ * @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.
+ */
+static DECLCALLBACK(size_t) rtlogPhaseWrite(void *pvArg, const char *pachChars, size_t cbChars)
+{
+ PRTLOGGER pLogger = (PRTLOGGER)pvArg;
+ RTFileWrite(pLogger->pInt->hFile, pachChars, cbChars, NULL);
+ return cbChars;
+}
+
+
+/**
+ * Callback to format VBox formatting extentions.
+ * See @ref pg_rt_str_format for a reference on the format types.
+ *
+ * @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'.
+ */
+static DECLCALLBACK(size_t) rtlogPhaseFormatStr(void *pvArg, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
+ const char **ppszFormat, va_list *pArgs, int cchWidth,
+ int cchPrecision, unsigned fFlags, char chArgSize)
+{
+ char ch = *(*ppszFormat)++;
+
+ AssertMsgFailed(("Invalid logger phase format type '%%%c%.10s'!\n", ch, *ppszFormat)); NOREF(ch);
+
+ return 0;
+}
+
+# endif /* SOME_UNUSED_FUNCTION */
+
+
+/**
+ * Log phase callback function, assumes the lock is already held
+ *
+ * @param pLogger The logger instance.
+ * @param pszFormat Format string.
+ * @param ... Optional arguments as specified in the format string.
+ */
+static DECLCALLBACK(void) rtlogPhaseMsgLocked(PRTLOGGER pLogger, const char *pszFormat, ...)
+{
+ va_list args;
+ AssertPtrReturnVoid(pLogger);
+ AssertPtrReturnVoid(pLogger->pInt);
+ Assert(pLogger->pInt->hSpinMtx != NIL_RTSEMSPINMUTEX);
+
+ va_start(args, pszFormat);
+ rtlogLoggerExVLocked(pLogger, 0, ~0U, pszFormat, args);
+ va_end(args);
+}
+
+
+/**
+ * Log phase callback function, assumes the lock is not held.
+ *
+ * @param pLogger The logger instance.
+ * @param pszFormat Format string.
+ * @param ... Optional arguments as specified in the format string.
+ */
+static DECLCALLBACK(void) rtlogPhaseMsgNormal(PRTLOGGER pLogger, const char *pszFormat, ...)
+{
+ va_list args;
+ AssertPtrReturnVoid(pLogger);
+ AssertPtrReturnVoid(pLogger->pInt);
+ Assert(pLogger->pInt->hSpinMtx != NIL_RTSEMSPINMUTEX);
+
+ va_start(args, pszFormat);
+ RTLogLoggerExV(pLogger, 0, ~0U, pszFormat, args);
+ va_end(args);
+}
+
+# endif /* IN_RING3 */
+
+/**
+ * Adjusts the ring buffer.
+ *
+ * @returns IPRT status code.
+ * @param pLogger The logger instance.
+ * @param cbNewSize The new ring buffer size (0 == default).
+ * @param fForce Whether to do this even if the logger instance hasn't
+ * really been fully created yet (i.e. during RTLogCreate).
+ */
+static int rtLogRingBufAdjust(PRTLOGGER pLogger, uint32_t cbNewSize, bool fForce)
+{
+ /*
+ * If this is early logger init, don't do anything.
+ */
+ if (!pLogger->pInt->fCreated && !fForce)
+ return VINF_SUCCESS;
+
+ /*
+ * Lock the logger and make the necessary changes.
+ */
+ int rc = rtlogLock(pLogger);
+ if (RT_SUCCESS(rc))
+ {
+ if (cbNewSize == 0)
+ cbNewSize = RTLOG_RINGBUF_DEFAULT_SIZE;
+ if ( pLogger->pInt->cbRingBuf != cbNewSize
+ || !pLogger->pInt->pchRingBufCur)
+ {
+ uintptr_t offOld = pLogger->pInt->pchRingBufCur - pLogger->pInt->pszRingBuf;
+ if (offOld < sizeof(RTLOG_RINGBUF_EYE_CATCHER))
+ offOld = sizeof(RTLOG_RINGBUF_EYE_CATCHER);
+ else if (offOld >= cbNewSize)
+ {
+ memmove(pLogger->pInt->pszRingBuf, &pLogger->pInt->pszRingBuf[offOld - cbNewSize], cbNewSize);
+ offOld = sizeof(RTLOG_RINGBUF_EYE_CATCHER);
+ }
+
+ void *pvNew = RTMemRealloc(pLogger->pInt->pchRingBufCur, cbNewSize);
+ if (pvNew)
+ {
+ pLogger->pInt->pszRingBuf = (char *)pvNew;
+ pLogger->pInt->pchRingBufCur = (char *)pvNew + offOld;
+ pLogger->pInt->cbRingBuf = cbNewSize;
+ memcpy(pvNew, RTLOG_RINGBUF_EYE_CATCHER, sizeof(RTLOG_RINGBUF_EYE_CATCHER));
+ memcpy((char *)pvNew + cbNewSize - sizeof(RTLOG_RINGBUF_EYE_CATCHER_END),
+ RTLOG_RINGBUF_EYE_CATCHER_END, sizeof(RTLOG_RINGBUF_EYE_CATCHER_END));
+ rc = VINF_SUCCESS;
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ }
+ rtlogUnlock(pLogger);
+ }
+
+ return rc;
+}
+
+
+/**
+ * Writes text to the ring buffer.
+ *
+ * @param pInt The internal logger data structure.
+ * @param pachText The text to write.
+ * @param cchText The number of chars (bytes) to write.
+ */
+static void rtLogRingBufWrite(PRTLOGGERINTERNAL pInt, const char *pachText, size_t cchText)
+{
+ /*
+ * Get the ring buffer data, adjusting it to only describe the writable
+ * part of the buffer.
+ */
+ char * const pchStart = &pInt->pszRingBuf[sizeof(RTLOG_RINGBUF_EYE_CATCHER)];
+ size_t const cchBuf = pInt->cbRingBuf - sizeof(RTLOG_RINGBUF_EYE_CATCHER) - sizeof(RTLOG_RINGBUF_EYE_CATCHER_END);
+ char *pchCur = pInt->pchRingBufCur;
+ size_t cchLeft = pchCur - pchStart;
+ if (RT_LIKELY(cchLeft < cchBuf))
+ cchLeft = cchBuf - cchLeft;
+ else
+ {
+ /* May happen in ring-0 where a thread or two went ahead without getting the lock. */
+ pchCur = pchStart;
+ cchLeft = cchBuf;
+ }
+ Assert(cchBuf < pInt->cbRingBuf);
+
+ if (cchText < cchLeft)
+ {
+ /*
+ * The text fits in the remaining space.
+ */
+ memcpy(pchCur, pachText, cchText);
+ pchCur[cchText] = '\0';
+ pInt->pchRingBufCur = &pchCur[cchText];
+ pInt->cbRingBufUnflushed += cchText;
+ }
+ else
+ {
+ /*
+ * The text wraps around. Taking the simple but inefficient approach
+ * to input texts that are longer than the ring buffer since that
+ * is unlikely to the be a frequent case.
+ */
+ /* Fill to the end of the buffer. */
+ memcpy(pchCur, pachText, cchLeft);
+ pachText += cchLeft;
+ cchText -= cchLeft;
+ pInt->cbRingBufUnflushed += cchLeft;
+ pInt->pchRingBufCur = pchStart;
+
+ /* Ring buffer overflows (the plainly inefficient bit). */
+ while (cchText >= cchBuf)
+ {
+ memcpy(pchStart, pachText, cchBuf);
+ pachText += cchBuf;
+ cchText -= cchBuf;
+ pInt->cbRingBufUnflushed += cchBuf;
+ }
+
+ /* The final bit, if any. */
+ if (cchText > 0)
+ {
+ memcpy(pchStart, pachText, cchText);
+ pInt->cbRingBufUnflushed += cchText;
+ }
+ pchStart[cchText] = '\0';
+ pInt->pchRingBufCur = &pchStart[cchText];
+ }
+}
+
+
+/**
+ * Flushes the ring buffer to all the other log destinations.
+ *
+ * @param pLogger The logger instance which ring buffer should be flushed.
+ */
+static void rtLogRingBufFlush(PRTLOGGER pLogger)
+{
+ const char *pszPreamble;
+ size_t cchPreamble;
+ const char *pszFirst;
+ size_t cchFirst;
+ const char *pszSecond;
+ size_t cchSecond;
+
+ /*
+ * Get the ring buffer data, adjusting it to only describe the writable
+ * part of the buffer.
+ */
+ uint64_t cchUnflushed = pLogger->pInt->cbRingBufUnflushed;
+ char * const pszBuf = &pLogger->pInt->pszRingBuf[sizeof(RTLOG_RINGBUF_EYE_CATCHER)];
+ size_t const cchBuf = pLogger->pInt->cbRingBuf - sizeof(RTLOG_RINGBUF_EYE_CATCHER) - sizeof(RTLOG_RINGBUF_EYE_CATCHER_END);
+ size_t offCur = pLogger->pInt->pchRingBufCur - pszBuf;
+ size_t cchAfter;
+ if (RT_LIKELY(offCur < cchBuf))
+ cchAfter = cchBuf - offCur;
+ else /* May happen in ring-0 where a thread or two went ahead without getting the lock. */
+ {
+ offCur = 0;
+ cchAfter = cchBuf;
+ }
+
+ pLogger->pInt->cbRingBufUnflushed = 0;
+
+ /*
+ * Figure out whether there are one or two segments that needs writing,
+ * making the last segment is terminated. (The first is always
+ * terminated because of the eye-catcher at the end of the buffer.)
+ */
+ if (cchUnflushed == 0)
+ return;
+ pszBuf[offCur] = '\0';
+ if (cchUnflushed >= cchBuf)
+ {
+ pszFirst = &pszBuf[offCur + 1];
+ cchFirst = cchAfter ? cchAfter - 1 : 0;
+ pszSecond = pszBuf;
+ cchSecond = offCur;
+ pszPreamble = "\n*FLUSH RING BUF*\n";
+ cchPreamble = sizeof("\n*FLUSH RING BUF*\n") - 1;
+ }
+ else if ((size_t)cchUnflushed <= offCur)
+ {
+ cchFirst = (size_t)cchUnflushed;
+ pszFirst = &pszBuf[offCur - cchFirst];
+ pszSecond = "";
+ cchSecond = 0;
+ pszPreamble = "";
+ cchPreamble = 0;
+ }
+ else
+ {
+ cchFirst = (size_t)cchUnflushed - offCur;
+ pszFirst = &pszBuf[cchBuf - cchFirst];
+ pszSecond = pszBuf;
+ cchSecond = offCur;
+ pszPreamble = "";
+ cchPreamble = 0;
+ }
+
+ /*
+ * Write the ring buffer to all other destiations.
+ */
+ if (pLogger->fDestFlags & RTLOGDEST_USER)
+ {
+ if (cchPreamble)
+ RTLogWriteUser(pszPreamble, cchPreamble);
+ if (cchFirst)
+ RTLogWriteUser(pszFirst, cchFirst);
+ if (cchSecond)
+ RTLogWriteUser(pszSecond, cchSecond);
+ }
+
+ if (pLogger->fDestFlags & RTLOGDEST_DEBUGGER)
+ {
+ if (cchPreamble)
+ RTLogWriteDebugger(pszPreamble, cchPreamble);
+ if (cchFirst)
+ RTLogWriteDebugger(pszFirst, cchFirst);
+ if (cchSecond)
+ RTLogWriteDebugger(pszSecond, cchSecond);
+ }
+
+# ifdef IN_RING3
+ if (pLogger->fDestFlags & RTLOGDEST_FILE)
+ {
+ if (pLogger->pInt->hFile != NIL_RTFILE)
+ {
+ if (cchPreamble)
+ RTFileWrite(pLogger->pInt->hFile, pszPreamble, cchPreamble, NULL);
+ if (cchFirst)
+ RTFileWrite(pLogger->pInt->hFile, pszFirst, cchFirst, NULL);
+ if (cchSecond)
+ RTFileWrite(pLogger->pInt->hFile, pszSecond, cchSecond, NULL);
+ if (pLogger->fFlags & RTLOGFLAGS_FLUSH)
+ RTFileFlush(pLogger->pInt->hFile);
+ }
+ if (pLogger->pInt->cHistory)
+ pLogger->pInt->cbHistoryFileWritten += cchFirst + cchSecond;
+ }
+# endif
+
+ if (pLogger->fDestFlags & RTLOGDEST_STDOUT)
+ {
+ if (cchPreamble)
+ RTLogWriteStdOut(pszPreamble, cchPreamble);
+ if (cchFirst)
+ RTLogWriteStdOut(pszFirst, cchFirst);
+ if (cchSecond)
+ RTLogWriteStdOut(pszSecond, cchSecond);
+ }
+
+ if (pLogger->fDestFlags & RTLOGDEST_STDERR)
+ {
+ if (cchPreamble)
+ RTLogWriteStdErr(pszPreamble, cchPreamble);
+ if (cchFirst)
+ RTLogWriteStdErr(pszFirst, cchFirst);
+ if (cchSecond)
+ RTLogWriteStdErr(pszSecond, cchSecond);
+ }
+
+# if defined(IN_RING0) && !defined(LOG_NO_COM)
+ if (pLogger->fDestFlags & RTLOGDEST_COM)
+ {
+ if (cchPreamble)
+ RTLogWriteCom(pszPreamble, cchPreamble);
+ if (cchFirst)
+ RTLogWriteCom(pszFirst, cchFirst);
+ if (cchSecond)
+ RTLogWriteCom(pszSecond, cchSecond);
+ }
+# endif
+}
+
+
+
+
+RTDECL(int) RTLogCreateExV(PRTLOGGER *ppLogger, uint32_t fFlags, const char *pszGroupSettings,
+ const char *pszEnvVarBase, unsigned cGroups, const char * const *papszGroups,
+ uint32_t fDestFlags, PFNRTLOGPHASE pfnPhase, uint32_t cHistory,
+ uint64_t cbHistoryFileMax, uint32_t cSecsHistoryTimeSlot,
+ char *pszErrorMsg, size_t cchErrorMsg, const char *pszFilenameFmt, va_list args)
+{
+ int rc;
+ size_t offInternal;
+ size_t cbLogger;
+ PRTLOGGER pLogger;
+
+ /*
+ * Validate input.
+ */
+ if ( (cGroups && !papszGroups)
+ || !VALID_PTR(ppLogger) )
+ {
+ AssertMsgFailed(("Invalid parameters!\n"));
+ return VERR_INVALID_PARAMETER;
+ }
+ *ppLogger = NULL;
+
+ if (pszErrorMsg)
+ RTStrPrintf(pszErrorMsg, cchErrorMsg, N_("unknown error"));
+
+ AssertMsgReturn(cHistory < _1M, ("%#x", cHistory), VERR_OUT_OF_RANGE);
+
+ /*
+ * Allocate a logger instance.
+ */
+ offInternal = RT_OFFSETOF(RTLOGGER, afGroups[cGroups]);
+ offInternal = RT_ALIGN_Z(offInternal, sizeof(uint64_t));
+ cbLogger = offInternal + sizeof(RTLOGGERINTERNAL);
+ if (fFlags & RTLOGFLAGS_RESTRICT_GROUPS)
+ cbLogger += cGroups * sizeof(uint32_t);
+ pLogger = (PRTLOGGER)RTMemAllocZVar(cbLogger);
+ if (pLogger)
+ {
+# if defined(RT_ARCH_X86) && (!defined(LOG_USE_C99) || !defined(RT_WITHOUT_EXEC_ALLOC))
+ uint8_t *pu8Code;
+# endif
+ pLogger->u32Magic = RTLOGGER_MAGIC;
+ pLogger->cGroups = cGroups;
+ pLogger->fFlags = fFlags;
+ pLogger->fDestFlags = fDestFlags;
+ pLogger->pInt = (PRTLOGGERINTERNAL)((uintptr_t)pLogger + offInternal);
+ pLogger->pInt->uRevision = RTLOGGERINTERNAL_REV;
+ pLogger->pInt->cbSelf = sizeof(RTLOGGERINTERNAL);
+ pLogger->pInt->hSpinMtx = NIL_RTSEMSPINMUTEX;
+ pLogger->pInt->pfnFlush = NULL;
+ pLogger->pInt->pfnPrefix = NULL;
+ pLogger->pInt->pvPrefixUserArg = NULL;
+ pLogger->pInt->afPadding1[0] = false;
+ pLogger->pInt->afPadding1[1] = false;
+ pLogger->pInt->fCreated = false;
+ pLogger->pInt->cMaxGroups = cGroups;
+ pLogger->pInt->papszGroups = papszGroups;
+ if (fFlags & RTLOGFLAGS_RESTRICT_GROUPS)
+ pLogger->pInt->pacEntriesPerGroup = (uint32_t *)(pLogger->pInt + 1);
+ else
+ pLogger->pInt->pacEntriesPerGroup = NULL;
+ pLogger->pInt->cMaxEntriesPerGroup = UINT32_MAX;
+# ifdef IN_RING3
+ pLogger->pInt->pfnPhase = pfnPhase;
+ pLogger->pInt->hFile = NIL_RTFILE;
+ pLogger->pInt->cHistory = cHistory;
+ if (cbHistoryFileMax == 0)
+ pLogger->pInt->cbHistoryFileMax = UINT64_MAX;
+ else
+ pLogger->pInt->cbHistoryFileMax = cbHistoryFileMax;
+ if (cSecsHistoryTimeSlot == 0)
+ pLogger->pInt->cSecsHistoryTimeSlot = UINT32_MAX;
+ else
+ pLogger->pInt->cSecsHistoryTimeSlot = cSecsHistoryTimeSlot;
+# else /* !IN_RING3 */
+ RT_NOREF_PV(pfnPhase); RT_NOREF_PV(cHistory); RT_NOREF_PV(cbHistoryFileMax); RT_NOREF_PV(cSecsHistoryTimeSlot);
+# endif /* !IN_RING3 */
+ if (pszGroupSettings)
+ RTLogGroupSettings(pLogger, pszGroupSettings);
+
+# if defined(RT_ARCH_X86) && (!defined(LOG_USE_C99) || !defined(RT_WITHOUT_EXEC_ALLOC))
+ /*
+ * Emit wrapper code.
+ */
+ pu8Code = (uint8_t *)RTMemExecAlloc(64);
+ if (pu8Code)
+ {
+ pLogger->pfnLogger = *(PFNRTLOGGER*)&pu8Code;
+ *pu8Code++ = 0x68; /* push imm32 */
+ *(void **)pu8Code = pLogger;
+ pu8Code += sizeof(void *);
+ *pu8Code++ = 0xe8; /* call rel32 */
+ *(uint32_t *)pu8Code = (uintptr_t)RTLogLogger - ((uintptr_t)pu8Code + sizeof(uint32_t));
+ pu8Code += sizeof(uint32_t);
+ *pu8Code++ = 0x8d; /* lea esp, [esp + 4] */
+ *pu8Code++ = 0x64;
+ *pu8Code++ = 0x24;
+ *pu8Code++ = 0x04;
+ *pu8Code++ = 0xc3; /* ret near */
+ AssertMsg((uintptr_t)pu8Code - (uintptr_t)pLogger->pfnLogger <= 64,
+ ("Wrapper assembly is too big! %d bytes\n", (uintptr_t)pu8Code - (uintptr_t)pLogger->pfnLogger));
+ rc = VINF_SUCCESS;
+ }
+ else
+ {
+# ifdef RT_OS_LINUX
+ if (pszErrorMsg) /* Most probably SELinux causing trouble since the larger RTMemAlloc succeeded. */
+ RTStrPrintf(pszErrorMsg, cchErrorMsg, N_("mmap(PROT_WRITE | PROT_EXEC) failed -- SELinux?"));
+# endif
+ rc = VERR_NO_MEMORY;
+ }
+ if (RT_SUCCESS(rc))
+# endif /* X86 wrapper code*/
+ {
+# ifdef IN_RING3 /* files and env.vars. are only accessible when in R3 at the present time. */
+ /*
+ * Format the filename.
+ */
+ if (pszFilenameFmt)
+ {
+ /** @todo validate the length, fail on overflow. */
+ RTStrPrintfV(pLogger->pInt->szFilename, sizeof(pLogger->pInt->szFilename), pszFilenameFmt, args);
+ pLogger->fDestFlags |= RTLOGDEST_FILE;
+ }
+
+ /*
+ * Parse the environment variables.
+ */
+ if (pszEnvVarBase)
+ {
+ /* make temp copy of environment variable base. */
+ size_t cchEnvVarBase = strlen(pszEnvVarBase);
+ char *pszEnvVar = (char *)alloca(cchEnvVarBase + 16);
+ memcpy(pszEnvVar, pszEnvVarBase, cchEnvVarBase);
+
+ /*
+ * Destination.
+ */
+ strcpy(pszEnvVar + cchEnvVarBase, "_DEST");
+ const char *pszValue = RTEnvGet(pszEnvVar);
+ if (pszValue)
+ RTLogDestinations(pLogger, pszValue);
+
+ /*
+ * The flags.
+ */
+ strcpy(pszEnvVar + cchEnvVarBase, "_FLAGS");
+ pszValue = RTEnvGet(pszEnvVar);
+ if (pszValue)
+ RTLogFlags(pLogger, pszValue);
+
+ /*
+ * The group settings.
+ */
+ pszEnvVar[cchEnvVarBase] = '\0';
+ pszValue = RTEnvGet(pszEnvVar);
+ if (pszValue)
+ RTLogGroupSettings(pLogger, pszValue);
+ }
+# else /* !IN_RING3 */
+ RT_NOREF_PV(pszEnvVarBase); RT_NOREF_PV(pszFilenameFmt); RT_NOREF_PV(args);
+# endif /* !IN_RING3 */
+
+ /*
+ * Open the destination(s).
+ */
+ rc = VINF_SUCCESS;
+# ifdef IN_RING3
+ if (pLogger->fDestFlags & RTLOGDEST_FILE)
+ {
+ if (pLogger->fFlags & RTLOGFLAGS_APPEND)
+ {
+ rc = rtlogFileOpen(pLogger, pszErrorMsg, cchErrorMsg);
+
+ /* Rotate in case of appending to a too big log file,
+ otherwise this simply doesn't do anything. */
+ rtlogRotate(pLogger, 0, true /* fFirst */);
+ }
+ else
+ {
+ /* Force rotation if it is configured. */
+ pLogger->pInt->cbHistoryFileWritten = UINT64_MAX;
+ rtlogRotate(pLogger, 0, true /* fFirst */);
+
+ /* If the file is not open then rotation is not set up. */
+ if (pLogger->pInt->hFile == NIL_RTFILE)
+ {
+ pLogger->pInt->cbHistoryFileWritten = 0;
+ rc = rtlogFileOpen(pLogger, pszErrorMsg, cchErrorMsg);
+ }
+ }
+ }
+# endif /* IN_RING3 */
+
+ if ((pLogger->fDestFlags & RTLOGDEST_RINGBUF) && RT_SUCCESS(rc))
+ rc = rtLogRingBufAdjust(pLogger, pLogger->pInt->cbRingBuf, true /*fForce*/);
+
+ /*
+ * Create mutex and check how much it counts when entering the lock
+ * so that we can report the values for RTLOGFLAGS_PREFIX_LOCK_COUNTS.
+ */
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTSemSpinMutexCreate(&pLogger->pInt->hSpinMtx, RTSEMSPINMUTEX_FLAGS_IRQ_SAFE);
+ if (RT_SUCCESS(rc))
+ {
+# ifdef IN_RING3 /** @todo do counters in ring-0 too? */
+ RTTHREAD Thread = RTThreadSelf();
+ if (Thread != NIL_RTTHREAD)
+ {
+ int32_t c = RTLockValidatorWriteLockGetCount(Thread);
+ RTSemSpinMutexRequest(pLogger->pInt->hSpinMtx);
+ c = RTLockValidatorWriteLockGetCount(Thread) - c;
+ RTSemSpinMutexRelease(pLogger->pInt->hSpinMtx);
+ ASMAtomicWriteU32(&g_cLoggerLockCount, c);
+ }
+
+ /* Use the callback to generate some initial log contents. */
+ Assert(VALID_PTR(pLogger->pInt->pfnPhase) || pLogger->pInt->pfnPhase == NULL);
+ if (pLogger->pInt->pfnPhase)
+ pLogger->pInt->pfnPhase(pLogger, RTLOGPHASE_BEGIN, rtlogPhaseMsgNormal);
+# endif
+ pLogger->pInt->fCreated = true;
+ *ppLogger = pLogger;
+ return VINF_SUCCESS;
+ }
+
+ if (pszErrorMsg)
+ RTStrPrintf(pszErrorMsg, cchErrorMsg, N_("failed to create semaphore"));
+ }
+# ifdef IN_RING3
+ RTFileClose(pLogger->pInt->hFile);
+# endif
+# if defined(LOG_USE_C99) && defined(RT_WITHOUT_EXEC_ALLOC)
+ RTMemFree(*(void **)&pLogger->pfnLogger);
+# else
+ RTMemExecFree(*(void **)&pLogger->pfnLogger, 64);
+# endif
+ }
+ RTMemFree(pLogger);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTLogCreateExV);
+
+
+RTDECL(int) RTLogCreate(PRTLOGGER *ppLogger, uint32_t fFlags, const char *pszGroupSettings,
+ const char *pszEnvVarBase, unsigned cGroups, const char * const * papszGroups,
+ uint32_t fDestFlags, const char *pszFilenameFmt, ...)
+{
+ va_list args;
+ int rc;
+
+ va_start(args, pszFilenameFmt);
+ rc = RTLogCreateExV(ppLogger, fFlags, pszGroupSettings, pszEnvVarBase, cGroups, papszGroups,
+ fDestFlags, NULL /*pfnPhase*/, 0 /*cHistory*/, 0 /*cbHistoryFileMax*/, 0 /*cSecsHistoryTimeSlot*/,
+ NULL /*pszErrorMsg*/, 0 /*cchErrorMsg*/, pszFilenameFmt, args);
+ va_end(args);
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTLogCreate);
+
+
+RTDECL(int) RTLogCreateEx(PRTLOGGER *ppLogger, uint32_t fFlags, const char *pszGroupSettings,
+ const char *pszEnvVarBase, unsigned cGroups, const char * const * papszGroups,
+ uint32_t fDestFlags, PFNRTLOGPHASE pfnPhase, uint32_t cHistory,
+ uint64_t cbHistoryFileMax, uint32_t cSecsHistoryTimeSlot,
+ char *pszErrorMsg, size_t cchErrorMsg, const char *pszFilenameFmt, ...)
+{
+ va_list args;
+ int rc;
+
+ va_start(args, pszFilenameFmt);
+ rc = RTLogCreateExV(ppLogger, fFlags, pszGroupSettings, pszEnvVarBase, cGroups, papszGroups,
+ fDestFlags, pfnPhase, cHistory, cbHistoryFileMax, cSecsHistoryTimeSlot,
+ pszErrorMsg, cchErrorMsg, pszFilenameFmt, args);
+ va_end(args);
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTLogCreateEx);
+
+
+/**
+ * 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)
+{
+ int rc;
+ uint32_t iGroup;
+ RTSEMSPINMUTEX hSpinMtx;
+
+ /*
+ * Validate input.
+ */
+ if (!pLogger)
+ return VINF_SUCCESS;
+ AssertPtrReturn(pLogger, VERR_INVALID_POINTER);
+ AssertReturn(pLogger->u32Magic == RTLOGGER_MAGIC, VERR_INVALID_MAGIC);
+ AssertPtrReturn(pLogger->pInt, VERR_INVALID_POINTER);
+
+ /*
+ * Acquire logger instance sem and disable all logging. (paranoia)
+ */
+ rc = rtlogLock(pLogger);
+ AssertMsgRCReturn(rc, ("%Rrc\n", rc), rc);
+
+ pLogger->fFlags |= RTLOGFLAGS_DISABLED;
+ iGroup = pLogger->cGroups;
+ while (iGroup-- > 0)
+ pLogger->afGroups[iGroup] = 0;
+
+ /*
+ * Flush it.
+ */
+ rtlogFlush(pLogger);
+
+# ifdef IN_RING3
+ /*
+ * Add end of logging message.
+ */
+ if ( (pLogger->fDestFlags & RTLOGDEST_FILE)
+ && pLogger->pInt->hFile != NIL_RTFILE)
+ pLogger->pInt->pfnPhase(pLogger, RTLOGPHASE_END, rtlogPhaseMsgLocked);
+
+ /*
+ * Close output stuffs.
+ */
+ if (pLogger->pInt->hFile != NIL_RTFILE)
+ {
+ int rc2 = RTFileClose(pLogger->pInt->hFile);
+ AssertRC(rc2);
+ if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
+ rc = rc2;
+ pLogger->pInt->hFile = NIL_RTFILE;
+ }
+# endif
+
+ /*
+ * Free the mutex, the wrapper and the instance memory.
+ */
+ hSpinMtx = pLogger->pInt->hSpinMtx;
+ pLogger->pInt->hSpinMtx = NIL_RTSEMSPINMUTEX;
+ if (hSpinMtx != NIL_RTSEMSPINMUTEX)
+ {
+ int rc2;
+ RTSemSpinMutexRelease(hSpinMtx);
+ rc2 = RTSemSpinMutexDestroy(hSpinMtx);
+ AssertRC(rc2);
+ if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
+ rc = rc2;
+ }
+
+ if (pLogger->pfnLogger)
+ {
+# if defined(LOG_USE_C99) && defined(RT_WITHOUT_EXEC_ALLOC)
+ RTMemFree(*(void **)&pLogger->pfnLogger);
+# else
+ RTMemExecFree(*(void **)&pLogger->pfnLogger, 64);
+# endif
+ pLogger->pfnLogger = NULL;
+ }
+ RTMemFree(pLogger);
+
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTLogDestroy);
+
+
+/**
+ * Create a logger instance clone for RC usage.
+ *
+ * @returns iprt status code.
+ *
+ * @param pLogger The logger instance to be cloned.
+ * @param pLoggerRC Where to create the RC logger instance.
+ * @param cbLoggerRC Amount of memory allocated to for the RC logger
+ * instance clone.
+ * @param pfnLoggerRCPtr Pointer to logger wrapper function for this
+ * instance (RC Ptr).
+ * @param pfnFlushRCPtr Pointer to flush function (RC Ptr).
+ * @param fFlags Logger instance flags, a combination of the RTLOGFLAGS_* values.
+ */
+RTDECL(int) RTLogCloneRC(PRTLOGGER pLogger, PRTLOGGERRC pLoggerRC, size_t cbLoggerRC,
+ RTRCPTR pfnLoggerRCPtr, RTRCPTR pfnFlushRCPtr, uint32_t fFlags)
+{
+ /*
+ * Validate input.
+ */
+ if ( !pLoggerRC
+ || !pfnFlushRCPtr
+ || !pfnLoggerRCPtr)
+ {
+ AssertMsgFailed(("Invalid parameters!\n"));
+ return VERR_INVALID_PARAMETER;
+ }
+ if (cbLoggerRC < sizeof(*pLoggerRC))
+ {
+ AssertMsgFailed(("%d min=%d\n", cbLoggerRC, sizeof(*pLoggerRC)));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ /*
+ * Initialize GC instance.
+ */
+ pLoggerRC->offScratch = 0;
+ pLoggerRC->fPendingPrefix = false;
+ pLoggerRC->pfnLogger = pfnLoggerRCPtr;
+ pLoggerRC->pfnFlush = pfnFlushRCPtr;
+ pLoggerRC->u32Magic = RTLOGGERRC_MAGIC;
+ pLoggerRC->fFlags = fFlags | RTLOGFLAGS_DISABLED;
+ pLoggerRC->cGroups = 1;
+ pLoggerRC->afGroups[0] = 0;
+
+ /*
+ * Resolve defaults.
+ */
+ if (!pLogger)
+ {
+ pLogger = RTLogDefaultInstance();
+ if (!pLogger)
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Check if there's enough space for the groups.
+ */
+ if (cbLoggerRC < (size_t)RT_OFFSETOF(RTLOGGERRC, afGroups[pLogger->cGroups]))
+ {
+ AssertMsgFailed(("%d req=%d cGroups=%d\n", cbLoggerRC, RT_OFFSETOF(RTLOGGERRC, afGroups[pLogger->cGroups]), pLogger->cGroups));
+ return VERR_BUFFER_OVERFLOW;
+ }
+ memcpy(&pLoggerRC->afGroups[0], &pLogger->afGroups[0], pLogger->cGroups * sizeof(pLoggerRC->afGroups[0]));
+ pLoggerRC->cGroups = pLogger->cGroups;
+
+ /*
+ * Copy bits from the HC instance.
+ */
+ pLoggerRC->fPendingPrefix = pLogger->pInt->fPendingPrefix;
+ pLoggerRC->fFlags |= pLogger->fFlags;
+
+ /*
+ * Check if we can remove the disabled flag.
+ */
+ if ( pLogger->fDestFlags
+ && !((pLogger->fFlags | fFlags) & RTLOGFLAGS_DISABLED))
+ pLoggerRC->fFlags &= ~RTLOGFLAGS_DISABLED;
+
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTLogCloneRC);
+
+
+/**
+ * Flushes a RC logger instance to a R3 logger.
+ *
+ *
+ * @returns iprt status code.
+ * @param pLogger The R3 logger instance to flush pLoggerRC to. If NULL
+ * the default logger is used.
+ * @param pLoggerRC The RC logger instance to flush.
+ */
+RTDECL(void) RTLogFlushRC(PRTLOGGER pLogger, PRTLOGGERRC pLoggerRC)
+{
+ /*
+ * Resolve defaults.
+ */
+ if (!pLogger)
+ {
+ pLogger = RTLogDefaultInstance();
+ if (!pLogger)
+ {
+ pLoggerRC->offScratch = 0;
+ return;
+ }
+ }
+
+ /*
+ * Any thing to flush?
+ */
+ if ( pLogger->offScratch
+ || pLoggerRC->offScratch)
+ {
+ /*
+ * Acquire logger instance sem.
+ */
+ int rc = rtlogLock(pLogger);
+ if (RT_FAILURE(rc))
+ return;
+
+ /*
+ * Write whatever the GC instance contains to the HC one, and then
+ * flush the HC instance.
+ */
+ if (pLoggerRC->offScratch)
+ {
+ rtLogOutput(pLogger, pLoggerRC->achScratch, pLoggerRC->offScratch);
+ rtLogOutput(pLogger, NULL, 0);
+ pLoggerRC->offScratch = 0;
+ }
+
+ /*
+ * Release the semaphore.
+ */
+ rtlogUnlock(pLogger);
+ }
+}
+RT_EXPORT_SYMBOL(RTLogFlushRC);
+
+# ifdef IN_RING3
+
+RTDECL(int) RTLogCreateForR0(PRTLOGGER pLogger, size_t cbLogger,
+ RTR0PTR pLoggerR0Ptr, RTR0PTR pfnLoggerR0Ptr, RTR0PTR pfnFlushR0Ptr,
+ uint32_t fFlags, uint32_t fDestFlags)
+{
+ /*
+ * Validate input.
+ */
+ AssertPtrReturn(pLogger, VERR_INVALID_PARAMETER);
+ size_t const cbRequired = sizeof(*pLogger) + RTLOGGERINTERNAL_R0_SIZE;
+ AssertReturn(cbLogger >= cbRequired, VERR_BUFFER_OVERFLOW);
+ AssertReturn(pLoggerR0Ptr != NIL_RTR0PTR, VERR_INVALID_PARAMETER);
+ AssertReturn(pfnLoggerR0Ptr != NIL_RTR0PTR, VERR_INVALID_PARAMETER);
+
+ /*
+ * Initialize the ring-0 instance.
+ */
+ pLogger->achScratch[0] = 0;
+ pLogger->offScratch = 0;
+ pLogger->pfnLogger = (PFNRTLOGGER)pfnLoggerR0Ptr;
+ pLogger->fFlags = fFlags;
+ pLogger->fDestFlags = fDestFlags & ~RTLOGDEST_FILE;
+ pLogger->pInt = NULL;
+ pLogger->cGroups = 1;
+ pLogger->afGroups[0] = 0;
+
+ uint32_t cMaxGroups = (uint32_t)((cbLogger - cbRequired) / sizeof(pLogger->afGroups[0]));
+ if (fFlags & RTLOGFLAGS_RESTRICT_GROUPS)
+ cMaxGroups /= 2;
+ PRTLOGGERINTERNAL pInt;
+ for (;;)
+ {
+ AssertReturn(cMaxGroups > 0, VERR_BUFFER_OVERFLOW);
+ pInt = (PRTLOGGERINTERNAL)&pLogger->afGroups[cMaxGroups];
+ if (!((uintptr_t)pInt & (sizeof(uint64_t) - 1)))
+ break;
+ cMaxGroups--;
+ }
+ pLogger->pInt = (PRTLOGGERINTERNAL)(pLoggerR0Ptr + (uintptr_t)pInt - (uintptr_t)pLogger);
+ pInt->uRevision = RTLOGGERINTERNAL_REV;
+ pInt->cbSelf = RTLOGGERINTERNAL_R0_SIZE;
+ pInt->hSpinMtx = NIL_RTSEMSPINMUTEX; /* Not serialized. */
+ pInt->pfnFlush = (PFNRTLOGFLUSH)pfnFlushR0Ptr;
+ pInt->pfnPrefix = NULL;
+ pInt->pvPrefixUserArg = NULL;
+ pInt->fPendingPrefix = false;
+ pInt->cMaxGroups = cMaxGroups;
+ pInt->papszGroups = NULL;
+ pInt->cMaxEntriesPerGroup = UINT32_MAX;
+ if (fFlags & RTLOGFLAGS_RESTRICT_GROUPS)
+ {
+ memset(pInt + 1, 0, sizeof(uint32_t) * cMaxGroups);
+ pInt->pacEntriesPerGroup= (uint32_t *)(pLogger->pInt + 1);
+ }
+ else
+ pInt->pacEntriesPerGroup= NULL;
+
+ pInt->fCreated = true;
+ pLogger->u32Magic = RTLOGGER_MAGIC;
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTLogCreateForR0);
+
+
+RTDECL(size_t) RTLogCalcSizeForR0(uint32_t cGroups, uint32_t fFlags)
+{
+ size_t cb = RT_OFFSETOF(RTLOGGER, afGroups[cGroups]);
+ cb = RT_ALIGN_Z(cb, sizeof(uint64_t));
+ cb += sizeof(RTLOGGERINTERNAL);
+ if (fFlags & RTLOGFLAGS_RESTRICT_GROUPS)
+ cb += sizeof(uint32_t) * cGroups;
+ return cb;
+}
+RT_EXPORT_SYMBOL(RTLogCalcSizeForR0);
+
+
+RTDECL(int) RTLogCopyGroupsAndFlagsForR0(PRTLOGGER pDstLogger, RTR0PTR pDstLoggerR0Ptr,
+ PCRTLOGGER pSrcLogger, uint32_t fFlagsOr, uint32_t fFlagsAnd)
+{
+ /*
+ * Validate input.
+ */
+ AssertPtrReturn(pDstLogger, VERR_INVALID_PARAMETER);
+ AssertPtrNullReturn(pSrcLogger, VERR_INVALID_PARAMETER);
+
+ /*
+ * Resolve defaults.
+ */
+ if (!pSrcLogger)
+ {
+ pSrcLogger = RTLogDefaultInstance();
+ if (!pSrcLogger)
+ {
+ pDstLogger->fFlags |= RTLOGFLAGS_DISABLED | fFlagsOr;
+ pDstLogger->cGroups = 1;
+ pDstLogger->afGroups[0] = 0;
+ return VINF_SUCCESS;
+ }
+ }
+
+ /*
+ * Copy flags and group settings.
+ */
+ pDstLogger->fFlags = (pSrcLogger->fFlags & fFlagsAnd & ~RTLOGFLAGS_RESTRICT_GROUPS) | fFlagsOr;
+
+ PRTLOGGERINTERNAL pDstInt = (PRTLOGGERINTERNAL)((uintptr_t)pDstLogger->pInt - pDstLoggerR0Ptr + (uintptr_t)pDstLogger);
+ int rc = VINF_SUCCESS;
+ uint32_t cGroups = pSrcLogger->cGroups;
+ if (cGroups > pDstInt->cMaxGroups)
+ {
+ AssertMsgFailed(("cMaxGroups=%zd cGroups=%zd (min size %d)\n", pDstInt->cMaxGroups,
+ pSrcLogger->cGroups, RT_OFFSETOF(RTLOGGER, afGroups[pSrcLogger->cGroups]) + RTLOGGERINTERNAL_R0_SIZE));
+ rc = VERR_INVALID_PARAMETER;
+ cGroups = pDstInt->cMaxGroups;
+ }
+ memcpy(&pDstLogger->afGroups[0], &pSrcLogger->afGroups[0], cGroups * sizeof(pDstLogger->afGroups[0]));
+ pDstLogger->cGroups = cGroups;
+
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTLogCopyGroupsAndFlagsForR0);
+
+
+RTDECL(int) RTLogSetCustomPrefixCallbackForR0(PRTLOGGER pLogger, RTR0PTR pLoggerR0Ptr,
+ RTR0PTR pfnCallbackR0Ptr, RTR0PTR pvUserR0Ptr)
+{
+ AssertPtrReturn(pLogger, VERR_INVALID_POINTER);
+ AssertReturn(pLogger->u32Magic == RTLOGGER_MAGIC, VERR_INVALID_MAGIC);
+
+ /*
+ * Do the work.
+ */
+ PRTLOGGERINTERNAL pInt = (PRTLOGGERINTERNAL)((uintptr_t)pLogger->pInt - pLoggerR0Ptr + (uintptr_t)pLogger);
+ AssertReturn(pInt->uRevision == RTLOGGERINTERNAL_REV, VERR_LOG_REVISION_MISMATCH);
+ pInt->pvPrefixUserArg = (void *)pvUserR0Ptr;
+ pInt->pfnPrefix = (PFNRTLOGPREFIX)pfnCallbackR0Ptr;
+
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTLogSetCustomPrefixCallbackForR0);
+
+RTDECL(void) RTLogFlushR0(PRTLOGGER pLogger, PRTLOGGER pLoggerR0)
+{
+ /*
+ * Resolve defaults.
+ */
+ if (!pLogger)
+ {
+ pLogger = RTLogDefaultInstance();
+ if (!pLogger)
+ {
+ /* flushing to "/dev/null". */
+ if (pLoggerR0->offScratch)
+ pLoggerR0->offScratch = 0;
+ return;
+ }
+ }
+
+ /*
+ * Anything to flush?
+ */
+ if ( pLoggerR0->offScratch
+ || pLogger->offScratch)
+ {
+ /*
+ * Acquire logger semaphores.
+ */
+ int rc = rtlogLock(pLogger);
+ if (RT_FAILURE(rc))
+ return;
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Write whatever the GC instance contains to the HC one, and then
+ * flush the HC instance.
+ */
+ if (pLoggerR0->offScratch)
+ {
+ rtLogOutput(pLogger, pLoggerR0->achScratch, pLoggerR0->offScratch);
+ rtLogOutput(pLogger, NULL, 0);
+ pLoggerR0->offScratch = 0;
+ }
+ }
+ rtlogUnlock(pLogger);
+ }
+}
+RT_EXPORT_SYMBOL(RTLogFlushR0);
+
+# endif /* IN_RING3 */
+
+
+/**
+ * Flushes the buffer in one logger instance onto another logger.
+ *
+ * @returns iprt status code.
+ *
+ * @param pSrcLogger The logger instance to flush.
+ * @param pDstLogger The logger instance to flush onto.
+ * If NULL the default logger will be used.
+ */
+RTDECL(void) RTLogFlushToLogger(PRTLOGGER pSrcLogger, PRTLOGGER pDstLogger)
+{
+ /*
+ * Resolve defaults.
+ */
+ if (!pDstLogger)
+ {
+ pDstLogger = RTLogDefaultInstance();
+ if (!pDstLogger)
+ {
+ /* flushing to "/dev/null". */
+ if (pSrcLogger->offScratch)
+ {
+ int rc = rtlogLock(pSrcLogger);
+ if (RT_SUCCESS(rc))
+ {
+ pSrcLogger->offScratch = 0;
+ rtlogUnlock(pSrcLogger);
+ }
+ }
+ return;
+ }
+ }
+
+ /*
+ * Any thing to flush?
+ */
+ if ( pSrcLogger->offScratch
+ || pDstLogger->offScratch)
+ {
+ /*
+ * Acquire logger semaphores.
+ */
+ int rc = rtlogLock(pDstLogger);
+ if (RT_FAILURE(rc))
+ return;
+ rc = rtlogLock(pSrcLogger);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Write whatever the GC instance contains to the HC one, and then
+ * flush the HC instance.
+ */
+ if (pSrcLogger->offScratch)
+ {
+ rtLogOutput(pDstLogger, pSrcLogger->achScratch, pSrcLogger->offScratch);
+ rtLogOutput(pDstLogger, NULL, 0);
+ pSrcLogger->offScratch = 0;
+ }
+
+ /*
+ * Release the semaphores.
+ */
+ rtlogUnlock(pSrcLogger);
+ }
+ rtlogUnlock(pDstLogger);
+ }
+}
+RT_EXPORT_SYMBOL(RTLogFlushToLogger);
+
+
+/**
+ * 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)
+{
+ /*
+ * Resolve defaults.
+ */
+ if (!pLogger)
+ {
+ pLogger = RTLogDefaultInstance();
+ if (!pLogger)
+ return VINF_SUCCESS;
+ }
+ AssertReturn(pLogger->u32Magic == RTLOGGER_MAGIC, VERR_INVALID_MAGIC);
+
+ /*
+ * Do the work.
+ */
+ rtlogLock(pLogger);
+ pLogger->pInt->pvPrefixUserArg = pvUser;
+ pLogger->pInt->pfnPrefix = pfnCallback;
+ rtlogUnlock(pLogger);
+
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTLogSetCustomPrefixCallback);
+
+
+/**
+ * Matches a group name with a pattern mask in an case insensitive manner (ASCII).
+ *
+ * @returns true if matching and *ppachMask set to the end of the pattern.
+ * @returns false if no match.
+ * @param pszGrp The group name.
+ * @param ppachMask Pointer to the pointer to the mask. Only wildcard supported is '*'.
+ * @param cchMask The length of the mask, including modifiers. The modifiers is why
+ * we update *ppachMask on match.
+ */
+static bool rtlogIsGroupMatching(const char *pszGrp, const char **ppachMask, size_t cchMask)
+{
+ const char *pachMask;
+
+ if (!pszGrp || !*pszGrp)
+ return false;
+ pachMask = *ppachMask;
+ for (;;)
+ {
+ if (RT_C_TO_LOWER(*pszGrp) != RT_C_TO_LOWER(*pachMask))
+ {
+ const char *pszTmp;
+
+ /*
+ * Check for wildcard and do a minimal match if found.
+ */
+ if (*pachMask != '*')
+ return false;
+
+ /* eat '*'s. */
+ do pachMask++;
+ while (--cchMask && *pachMask == '*');
+
+ /* is there more to match? */
+ if ( !cchMask
+ || *pachMask == '.'
+ || *pachMask == '=')
+ break; /* we're good */
+
+ /* do extremely minimal matching (fixme) */
+ pszTmp = strchr(pszGrp, RT_C_TO_LOWER(*pachMask));
+ if (!pszTmp)
+ pszTmp = strchr(pszGrp, RT_C_TO_UPPER(*pachMask));
+ if (!pszTmp)
+ return false;
+ pszGrp = pszTmp;
+ continue;
+ }
+
+ /* done? */
+ if (!*++pszGrp)
+ {
+ /* trailing wildcard is ok. */
+ do
+ {
+ pachMask++;
+ cchMask--;
+ } while (cchMask && *pachMask == '*');
+ if ( !cchMask
+ || *pachMask == '.'
+ || *pachMask == '=')
+ break; /* we're good */
+ return false;
+ }
+
+ if (!--cchMask)
+ return false;
+ pachMask++;
+ }
+
+ /* match */
+ *ppachMask = pachMask;
+ return true;
+}
+
+
+/**
+ * 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.
+ * @param pszValue Value to parse.
+ */
+RTDECL(int) RTLogGroupSettings(PRTLOGGER pLogger, const char *pszValue)
+{
+ /*
+ * Resolve defaults.
+ */
+ if (!pLogger)
+ {
+ pLogger = RTLogDefaultInstance();
+ if (!pLogger)
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Iterate the string.
+ */
+ while (*pszValue)
+ {
+ /*
+ * Skip prefixes (blanks, ;, + and -).
+ */
+ bool fEnabled = true;
+ char ch;
+ const char *pszStart;
+ unsigned i;
+ size_t cch;
+
+ while ((ch = *pszValue) == '+' || ch == '-' || ch == ' ' || ch == '\t' || ch == '\n' || ch == ';')
+ {
+ if (ch == '+' || ch == '-' || ch == ';')
+ fEnabled = ch != '-';
+ pszValue++;
+ }
+ if (!*pszValue)
+ break;
+
+ /*
+ * Find end.
+ */
+ pszStart = pszValue;
+ while ((ch = *pszValue) != '\0' && ch != '+' && ch != '-' && ch != ' ' && ch != '\t')
+ pszValue++;
+
+ /*
+ * Find the group (ascii case insensitive search).
+ * Special group 'all'.
+ */
+ cch = pszValue - pszStart;
+ if ( cch >= 3
+ && (pszStart[0] == 'a' || pszStart[0] == 'A')
+ && (pszStart[1] == 'l' || pszStart[1] == 'L')
+ && (pszStart[2] == 'l' || pszStart[2] == 'L')
+ && (cch == 3 || pszStart[3] == '.' || pszStart[3] == '='))
+ {
+ /*
+ * All.
+ */
+ unsigned fFlags = cch == 3
+ ? RTLOGGRPFLAGS_ENABLED | RTLOGGRPFLAGS_LEVEL_1
+ : rtlogGroupFlags(&pszStart[3]);
+ for (i = 0; i < pLogger->cGroups; i++)
+ {
+ if (fEnabled)
+ pLogger->afGroups[i] |= fFlags;
+ else
+ pLogger->afGroups[i] &= ~fFlags;
+ }
+ }
+ else
+ {
+ /*
+ * Specific group(s).
+ */
+ for (i = 0; i < pLogger->cGroups; i++)
+ {
+ const char *psz2 = (const char*)pszStart;
+ if (rtlogIsGroupMatching(pLogger->pInt->papszGroups[i], &psz2, cch))
+ {
+ unsigned fFlags = RTLOGGRPFLAGS_ENABLED | RTLOGGRPFLAGS_LEVEL_1;
+ if (*psz2 == '.' || *psz2 == '=')
+ fFlags = rtlogGroupFlags(psz2);
+ if (fEnabled)
+ pLogger->afGroups[i] |= fFlags;
+ else
+ pLogger->afGroups[i] &= ~fFlags;
+ }
+ } /* for each group */
+ }
+
+ } /* parse specification */
+
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTLogGroupSettings);
+
+
+/**
+ * Interprets the group flags suffix.
+ *
+ * @returns Flags specified. (0 is possible!)
+ * @param psz Start of Suffix. (Either dot or equal sign.)
+ */
+static unsigned rtlogGroupFlags(const char *psz)
+{
+ unsigned fFlags = 0;
+
+ /*
+ * Literal flags.
+ */
+ while (*psz == '.')
+ {
+ static struct
+ {
+ const char *pszFlag; /* lowercase!! */
+ unsigned fFlag;
+ } aFlags[] =
+ {
+ { "eo", RTLOGGRPFLAGS_ENABLED },
+ { "enabledonly",RTLOGGRPFLAGS_ENABLED },
+ { "e", RTLOGGRPFLAGS_ENABLED | RTLOGGRPFLAGS_LEVEL_1 | RTLOGGRPFLAGS_WARN },
+ { "enabled", RTLOGGRPFLAGS_ENABLED | RTLOGGRPFLAGS_LEVEL_1 | RTLOGGRPFLAGS_WARN },
+ { "l1", RTLOGGRPFLAGS_LEVEL_1 },
+ { "level1", RTLOGGRPFLAGS_LEVEL_1 },
+ { "l", RTLOGGRPFLAGS_LEVEL_2 },
+ { "l2", RTLOGGRPFLAGS_LEVEL_2 },
+ { "level2", RTLOGGRPFLAGS_LEVEL_2 },
+ { "l3", RTLOGGRPFLAGS_LEVEL_3 },
+ { "level3", RTLOGGRPFLAGS_LEVEL_3 },
+ { "l4", RTLOGGRPFLAGS_LEVEL_4 },
+ { "level4", RTLOGGRPFLAGS_LEVEL_4 },
+ { "l5", RTLOGGRPFLAGS_LEVEL_5 },
+ { "level5", RTLOGGRPFLAGS_LEVEL_5 },
+ { "l6", RTLOGGRPFLAGS_LEVEL_6 },
+ { "level6", RTLOGGRPFLAGS_LEVEL_6 },
+ { "l7", RTLOGGRPFLAGS_LEVEL_7 },
+ { "level7", RTLOGGRPFLAGS_LEVEL_7 },
+ { "l8", RTLOGGRPFLAGS_LEVEL_8 },
+ { "level8", RTLOGGRPFLAGS_LEVEL_8 },
+ { "l9", RTLOGGRPFLAGS_LEVEL_9 },
+ { "level9", RTLOGGRPFLAGS_LEVEL_9 },
+ { "l10", RTLOGGRPFLAGS_LEVEL_10 },
+ { "level10", RTLOGGRPFLAGS_LEVEL_10 },
+ { "l11", RTLOGGRPFLAGS_LEVEL_11 },
+ { "level11", RTLOGGRPFLAGS_LEVEL_11 },
+ { "l12", RTLOGGRPFLAGS_LEVEL_12 },
+ { "level12", RTLOGGRPFLAGS_LEVEL_12 },
+ { "f", RTLOGGRPFLAGS_FLOW },
+ { "flow", RTLOGGRPFLAGS_FLOW },
+ { "w", RTLOGGRPFLAGS_WARN },
+ { "warn", RTLOGGRPFLAGS_WARN },
+ { "warning", RTLOGGRPFLAGS_WARN },
+ { "restrict", RTLOGGRPFLAGS_RESTRICT },
+
+ };
+ unsigned i;
+ bool fFound = false;
+ psz++;
+ for (i = 0; i < RT_ELEMENTS(aFlags) && !fFound; i++)
+ {
+ const char *psz1 = aFlags[i].pszFlag;
+ const char *psz2 = psz;
+ while (*psz1 == RT_C_TO_LOWER(*psz2))
+ {
+ psz1++;
+ psz2++;
+ if (!*psz1)
+ {
+ if ( (*psz2 >= 'a' && *psz2 <= 'z')
+ || (*psz2 >= 'A' && *psz2 <= 'Z')
+ || (*psz2 >= '0' && *psz2 <= '9') )
+ break;
+ fFlags |= aFlags[i].fFlag;
+ fFound = true;
+ psz = psz2;
+ break;
+ }
+ } /* strincmp */
+ } /* for each flags */
+ AssertMsg(fFound, ("%.15s...", psz));
+ }
+
+ /*
+ * Flag value.
+ */
+ if (*psz == '=')
+ {
+ psz++;
+ if (*psz == '~')
+ fFlags = ~RTStrToInt32(psz + 1);
+ else
+ fFlags = RTStrToInt32(psz);
+ }
+
+ return fFlags;
+}
+
+/**
+ * Helper for RTLogGetGroupSettings.
+ */
+static int rtLogGetGroupSettingsAddOne(const char *pszName, uint32_t fGroup, char **ppszBuf, size_t *pcchBuf, bool *pfNotFirst)
+{
+# define APPEND_PSZ(psz,cch) do { memcpy(*ppszBuf, (psz), (cch)); *ppszBuf += (cch); *pcchBuf -= (cch); } while (0)
+# define APPEND_SZ(sz) APPEND_PSZ(sz, sizeof(sz) - 1)
+# define APPEND_CH(ch) do { **ppszBuf = (ch); *ppszBuf += 1; *pcchBuf -= 1; } while (0)
+
+ /*
+ * Add the name.
+ */
+ size_t cchName = strlen(pszName);
+ if (cchName + 1 + *pfNotFirst > *pcchBuf)
+ return VERR_BUFFER_OVERFLOW;
+ if (*pfNotFirst)
+ APPEND_CH(' ');
+ else
+ *pfNotFirst = true;
+ APPEND_PSZ(pszName, cchName);
+
+ /*
+ * Only generate mnemonics for the simple+common bits.
+ */
+ if (fGroup == (RTLOGGRPFLAGS_ENABLED | RTLOGGRPFLAGS_LEVEL_1))
+ /* nothing */;
+ else if ( fGroup == (RTLOGGRPFLAGS_ENABLED | RTLOGGRPFLAGS_LEVEL_1 | RTLOGGRPFLAGS_LEVEL_2 | RTLOGGRPFLAGS_FLOW)
+ && *pcchBuf >= sizeof(".e.l.f"))
+ APPEND_SZ(".e.l.f");
+ else if ( fGroup == (RTLOGGRPFLAGS_ENABLED | RTLOGGRPFLAGS_LEVEL_1 | RTLOGGRPFLAGS_FLOW)
+ && *pcchBuf >= sizeof(".e.f"))
+ APPEND_SZ(".e.f");
+ else if (*pcchBuf >= 1 + 10 + 1)
+ {
+ size_t cch;
+ APPEND_CH('=');
+ cch = RTStrFormatNumber(*ppszBuf, fGroup, 16, 0, 0, RTSTR_F_SPECIAL | RTSTR_F_32BIT);
+ *ppszBuf += cch;
+ *pcchBuf -= cch;
+ }
+ else
+ return VERR_BUFFER_OVERFLOW;
+
+# undef APPEND_PSZ
+# undef APPEND_SZ
+# undef APPEND_CH
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * 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) RTLogGetGroupSettings(PRTLOGGER pLogger, char *pszBuf, size_t cchBuf)
+{
+ bool fNotFirst = false;
+ int rc = VINF_SUCCESS;
+ uint32_t cGroups;
+ uint32_t fGroup;
+ uint32_t i;
+
+ Assert(cchBuf);
+
+ /*
+ * Resolve defaults.
+ */
+ if (!pLogger)
+ {
+ pLogger = RTLogDefaultInstance();
+ if (!pLogger)
+ {
+ *pszBuf = '\0';
+ return VINF_SUCCESS;
+ }
+ }
+
+ cGroups = pLogger->cGroups;
+
+ /*
+ * Check if all are the same.
+ */
+ fGroup = pLogger->afGroups[0];
+ for (i = 1; i < cGroups; i++)
+ if (pLogger->afGroups[i] != fGroup)
+ break;
+ if (i >= cGroups)
+ rc = rtLogGetGroupSettingsAddOne("all", fGroup, &pszBuf, &cchBuf, &fNotFirst);
+ else
+ {
+
+ /*
+ * Iterate all the groups and print all that are enabled.
+ */
+ for (i = 0; i < cGroups; i++)
+ {
+ fGroup = pLogger->afGroups[i];
+ if (fGroup)
+ {
+ const char *pszName = pLogger->pInt->papszGroups[i];
+ if (pszName)
+ {
+ rc = rtLogGetGroupSettingsAddOne(pszName, fGroup, &pszBuf, &cchBuf, &fNotFirst);
+ if (rc)
+ break;
+ }
+ }
+ }
+ }
+
+ *pszBuf = '\0';
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTLogGetGroupSettings);
+
+#endif /* !IN_RC */
+
+/**
+ * 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)
+{
+ int rc = VINF_SUCCESS;
+
+ /*
+ * Resolve defaults.
+ */
+ if (!pLogger)
+ {
+ pLogger = RTLogDefaultInstance();
+ if (!pLogger)
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Iterate the string.
+ */
+ while (*pszValue)
+ {
+ /* check no prefix. */
+ bool fNo = false;
+ char ch;
+ unsigned i;
+
+ /* skip blanks. */
+ while (RT_C_IS_SPACE(*pszValue))
+ pszValue++;
+ if (!*pszValue)
+ return rc;
+
+ while ((ch = *pszValue) != '\0')
+ {
+ if (ch == 'n' && pszValue[1] == 'o')
+ {
+ pszValue += 2;
+ fNo = !fNo;
+ }
+ else if (ch == '+')
+ {
+ pszValue++;
+ fNo = true;
+ }
+ else if (ch == '-' || ch == '!' || ch == '~')
+ {
+ pszValue++;
+ fNo = !fNo;
+ }
+ else
+ break;
+ }
+
+ /* instruction. */
+ for (i = 0; i < RT_ELEMENTS(g_aLogFlags); i++)
+ {
+ if (!strncmp(pszValue, g_aLogFlags[i].pszInstr, g_aLogFlags[i].cchInstr))
+ {
+ if (fNo == g_aLogFlags[i].fInverted)
+ pLogger->fFlags |= g_aLogFlags[i].fFlag;
+ else
+ pLogger->fFlags &= ~g_aLogFlags[i].fFlag;
+ pszValue += g_aLogFlags[i].cchInstr;
+ break;
+ }
+ }
+
+ /* unknown instruction? */
+ if (i >= RT_ELEMENTS(g_aLogFlags))
+ {
+ AssertMsgFailed(("Invalid flags! unknown instruction %.20s\n", pszValue));
+ pszValue++;
+ }
+
+ /* skip blanks and delimiters. */
+ while (RT_C_IS_SPACE(*pszValue) || *pszValue == ';')
+ pszValue++;
+ } /* while more environment variable value left */
+
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTLogFlags);
+
+
+/**
+ * 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)
+{
+ bool fOld;
+
+ /*
+ * Resolve the logger instance.
+ */
+ if (!pLogger)
+ {
+ pLogger = RTLogDefaultInstance();
+ if (!pLogger)
+ return false;
+ }
+
+ rtlogLock(pLogger);
+ fOld = !!(pLogger->fFlags & RTLOGFLAGS_BUFFERED);
+ if (fBuffered)
+ pLogger->fFlags |= RTLOGFLAGS_BUFFERED;
+ else
+ pLogger->fFlags &= ~RTLOGFLAGS_BUFFERED;
+ rtlogUnlock(pLogger);
+
+ return fOld;
+}
+RT_EXPORT_SYMBOL(RTLogSetBuffering);
+
+
+#ifdef IN_RING3
+RTDECL(uint32_t) RTLogSetGroupLimit(PRTLOGGER pLogger, uint32_t cMaxEntriesPerGroup)
+{
+ /*
+ * Resolve the logger instance.
+ */
+ if (!pLogger)
+ {
+ pLogger = RTLogDefaultInstance();
+ if (!pLogger)
+ return UINT32_MAX;
+ }
+
+ rtlogLock(pLogger);
+ uint32_t cOld = pLogger->pInt->cMaxEntriesPerGroup;
+ pLogger->pInt->cMaxEntriesPerGroup = cMaxEntriesPerGroup;
+ rtlogUnlock(pLogger);
+
+ return cOld;
+}
+#endif
+
+#ifndef IN_RC
+
+/**
+ * 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) RTLogGetFlags(PRTLOGGER pLogger, char *pszBuf, size_t cchBuf)
+{
+ bool fNotFirst = false;
+ int rc = VINF_SUCCESS;
+ uint32_t fFlags;
+ unsigned i;
+
+ Assert(cchBuf);
+
+ /*
+ * Resolve defaults.
+ */
+ if (!pLogger)
+ {
+ pLogger = RTLogDefaultInstance();
+ if (!pLogger)
+ {
+ *pszBuf = '\0';
+ return VINF_SUCCESS;
+ }
+ }
+
+ /*
+ * Add the flags in the list.
+ */
+ fFlags = pLogger->fFlags;
+ for (i = 0; i < RT_ELEMENTS(g_aLogFlags); i++)
+ if ( !g_aLogFlags[i].fInverted
+ ? (g_aLogFlags[i].fFlag & fFlags)
+ : !(g_aLogFlags[i].fFlag & fFlags))
+ {
+ size_t cchInstr = g_aLogFlags[i].cchInstr;
+ if (cchInstr + fNotFirst + 1 > cchBuf)
+ {
+ rc = VERR_BUFFER_OVERFLOW;
+ break;
+ }
+ if (fNotFirst)
+ {
+ *pszBuf++ = ' ';
+ cchBuf--;
+ }
+ memcpy(pszBuf, g_aLogFlags[i].pszInstr, cchInstr);
+ pszBuf += cchInstr;
+ cchBuf -= cchInstr;
+ fNotFirst = true;
+ }
+ *pszBuf = '\0';
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTLogGetFlags);
+
+
+/**
+ * Finds the end of a destination value.
+ *
+ * The value ends when we counter a ';' or a free standing word (space on both
+ * from the g_aLogDst table. (If this is problematic for someone, we could
+ * always do quoting and escaping.)
+ *
+ * @returns Value length in chars.
+ * @param pszValue The first char after '=' or ':'.
+ */
+static size_t rtLogDestFindValueLength(const char *pszValue)
+{
+ size_t off = 0;
+ char ch;
+ while ((ch = pszValue[off]) != '\0' && ch != ';')
+ {
+ if (!RT_C_IS_SPACE(ch))
+ off++;
+ else
+ {
+ unsigned i;
+ size_t cchThusFar = off;
+ do
+ off++;
+ while ((ch = pszValue[off]) != '\0' && RT_C_IS_SPACE(ch));
+ if (ch == ';')
+ return cchThusFar;
+
+ if (ch == 'n' && pszValue[off + 1] == 'o')
+ off += 2;
+ for (i = 0; i < RT_ELEMENTS(g_aLogDst); i++)
+ if (!strncmp(&pszValue[off], g_aLogDst[i].pszInstr, g_aLogDst[i].cchInstr))
+ {
+ ch = pszValue[off + g_aLogDst[i].cchInstr];
+ if (ch == '\0' || RT_C_IS_SPACE(ch) || ch == '=' || ch == ':' || ch == ';')
+ return cchThusFar;
+ }
+ }
+ }
+ return off;
+}
+
+
+/**
+ * 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)
+{
+ /*
+ * Resolve defaults.
+ */
+ if (!pLogger)
+ {
+ pLogger = RTLogDefaultInstance();
+ if (!pLogger)
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Do the parsing.
+ */
+ while (*pszValue)
+ {
+ bool fNo;
+ unsigned i;
+
+ /* skip blanks. */
+ while (RT_C_IS_SPACE(*pszValue))
+ pszValue++;
+ if (!*pszValue)
+ break;
+
+ /* check no prefix. */
+ fNo = false;
+ if (pszValue[0] == 'n' && pszValue[1] == 'o')
+ {
+ fNo = true;
+ pszValue += 2;
+ }
+
+ /* instruction. */
+ for (i = 0; i < RT_ELEMENTS(g_aLogDst); i++)
+ {
+ size_t cchInstr = strlen(g_aLogDst[i].pszInstr);
+ if (!strncmp(pszValue, g_aLogDst[i].pszInstr, cchInstr))
+ {
+ if (!fNo)
+ pLogger->fDestFlags |= g_aLogDst[i].fFlag;
+ else
+ pLogger->fDestFlags &= ~g_aLogDst[i].fFlag;
+ pszValue += cchInstr;
+
+ /* check for value. */
+ while (RT_C_IS_SPACE(*pszValue))
+ pszValue++;
+ if (*pszValue == '=' || *pszValue == ':')
+ {
+ pszValue++;
+ size_t cch = rtLogDestFindValueLength(pszValue);
+ const char *pszEnd = pszValue + cch;
+
+# ifdef IN_RING3
+ char szTmp[sizeof(pLogger->pInt->szFilename)];
+# else
+ char szTmp[32];
+# endif
+ if (0)
+ { /* nothing */ }
+#ifdef IN_RING3
+
+ /* log file name */
+ else if (i == 0 /* file */ && !fNo)
+ {
+ AssertReturn(cch < sizeof(pLogger->pInt->szFilename), VERR_OUT_OF_RANGE);
+ memcpy(pLogger->pInt->szFilename, pszValue, cch);
+ pLogger->pInt->szFilename[cch] = '\0';
+ /** @todo reopen log file if pLogger->pInt->fCreated is true ... */
+ }
+ /* log directory */
+ else if (i == 1 /* dir */ && !fNo)
+ {
+ const char *pszFile = RTPathFilename(pLogger->pInt->szFilename);
+ size_t cchFile = pszFile ? strlen(pszFile) : 0;
+ AssertReturn(cchFile + cch + 1 < sizeof(pLogger->pInt->szFilename), VERR_OUT_OF_RANGE);
+ memcpy(szTmp, cchFile ? pszFile : "", cchFile + 1);
+
+ memcpy(pLogger->pInt->szFilename, pszValue, cch);
+ pLogger->pInt->szFilename[cch] = '\0';
+ RTPathStripTrailingSlash(pLogger->pInt->szFilename);
+
+ cch = strlen(pLogger->pInt->szFilename);
+ pLogger->pInt->szFilename[cch++] = '/';
+ memcpy(&pLogger->pInt->szFilename[cch], szTmp, cchFile);
+ pLogger->pInt->szFilename[cch + cchFile] = '\0';
+ /** @todo reopen log file if pLogger->pInt->fCreated is true ... */
+ }
+ else if (i == 2 /* history */)
+ {
+ if (!fNo)
+ {
+ uint32_t cHistory = 0;
+ int rc = RTStrCopyEx(szTmp, sizeof(szTmp), pszValue, cch);
+ if (RT_SUCCESS(rc))
+ rc = RTStrToUInt32Full(szTmp, 0, &cHistory);
+ AssertMsgReturn(RT_SUCCESS(rc) && cHistory < _1M, ("Invalid history value %s (%Rrc)!\n", szTmp, rc), rc);
+ pLogger->pInt->cHistory = cHistory;
+ }
+ else
+ pLogger->pInt->cHistory = 0;
+ }
+ else if (i == 3 /* histsize */)
+ {
+ if (!fNo)
+ {
+ int rc = RTStrCopyEx(szTmp, sizeof(szTmp), pszValue, cch);
+ if (RT_SUCCESS(rc))
+ rc = RTStrToUInt64Full(szTmp, 0, &pLogger->pInt->cbHistoryFileMax);
+ AssertMsgRCReturn(rc, ("Invalid history file size value %s (%Rrc)!\n", szTmp, rc), rc);
+ if (pLogger->pInt->cbHistoryFileMax == 0)
+ pLogger->pInt->cbHistoryFileMax = UINT64_MAX;
+ }
+ else
+ pLogger->pInt->cbHistoryFileMax = UINT64_MAX;
+ }
+ else if (i == 4 /* histtime */)
+ {
+ if (!fNo)
+ {
+ int rc = RTStrCopyEx(szTmp, sizeof(szTmp), pszValue, cch);
+ if (RT_SUCCESS(rc))
+ rc = RTStrToUInt32Full(szTmp, 0, &pLogger->pInt->cSecsHistoryTimeSlot);
+ AssertMsgRCReturn(rc, ("Invalid history time slot value %s (%Rrc)!\n", szTmp, rc), rc);
+ if (pLogger->pInt->cSecsHistoryTimeSlot == 0)
+ pLogger->pInt->cSecsHistoryTimeSlot = UINT32_MAX;
+ }
+ else
+ pLogger->pInt->cSecsHistoryTimeSlot = UINT32_MAX;
+ }
+# endif /* IN_RING3 */
+ else if (i == 5 /* ringbuf */ && !fNo)
+ {
+ int rc = RTStrCopyEx(szTmp, sizeof(szTmp), pszValue, cch);
+ uint32_t cbRingBuf = 0;
+ if (RT_SUCCESS(rc))
+ rc = RTStrToUInt32Full(szTmp, 0, &cbRingBuf);
+ AssertMsgRCReturn(rc, ("Invalid ring buffer size value '%s' (%Rrc)!\n", szTmp, rc), rc);
+
+ if (cbRingBuf == 0)
+ cbRingBuf = RTLOG_RINGBUF_DEFAULT_SIZE;
+ else if (cbRingBuf < RTLOG_RINGBUF_MIN_SIZE)
+ cbRingBuf = RTLOG_RINGBUF_MIN_SIZE;
+ else if (cbRingBuf > RTLOG_RINGBUF_MAX_SIZE)
+ cbRingBuf = RTLOG_RINGBUF_MAX_SIZE;
+ else
+ cbRingBuf = RT_ALIGN_32(cbRingBuf, 64);
+ rc = rtLogRingBufAdjust(pLogger, cbRingBuf, false /*fForce*/);
+ if (RT_FAILURE(rc))
+ return rc;
+ }
+ else
+ AssertMsgFailedReturn(("Invalid destination value! %s%s doesn't take a value!\n",
+ fNo ? "no" : "", g_aLogDst[i].pszInstr),
+ VERR_INVALID_PARAMETER);
+
+ pszValue = pszEnd + (*pszEnd != '\0');
+ }
+ else if (i == 5 /* ringbuf */ && !fNo && !pLogger->pInt->pszRingBuf)
+ {
+ int rc = rtLogRingBufAdjust(pLogger, pLogger->pInt->cbRingBuf, false /*fForce*/);
+ if (RT_FAILURE(rc))
+ return rc;
+ }
+ break;
+ }
+ }
+
+ /* assert known instruction */
+ AssertMsgReturn(i < RT_ELEMENTS(g_aLogDst),
+ ("Invalid destination value! unknown instruction %.20s\n", pszValue),
+ VERR_INVALID_PARAMETER);
+
+ /* skip blanks and delimiters. */
+ while (RT_C_IS_SPACE(*pszValue) || *pszValue == ';')
+ pszValue++;
+ } /* while more environment variable value left */
+
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTLogDestinations);
+
+
+/**
+ * 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) RTLogGetDestinations(PRTLOGGER pLogger, char *pszBuf, size_t cchBuf)
+{
+ bool fNotFirst = false;
+ int rc = VINF_SUCCESS;
+ uint32_t fDestFlags;
+ unsigned i;
+
+ AssertReturn(cchBuf, VERR_INVALID_PARAMETER);
+ *pszBuf = '\0';
+
+ /*
+ * Resolve defaults.
+ */
+ if (!pLogger)
+ {
+ pLogger = RTLogDefaultInstance();
+ if (!pLogger)
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Add the flags in the list.
+ */
+ fDestFlags = pLogger->fDestFlags;
+ for (i = 6; i < RT_ELEMENTS(g_aLogDst); i++)
+ if (g_aLogDst[i].fFlag & fDestFlags)
+ {
+ if (fNotFirst)
+ {
+ rc = RTStrCopyP(&pszBuf, &cchBuf, " ");
+ if (RT_FAILURE(rc))
+ return rc;
+ }
+ rc = RTStrCopyP(&pszBuf, &cchBuf, g_aLogDst[i].pszInstr);
+ if (RT_FAILURE(rc))
+ return rc;
+ fNotFirst = true;
+ }
+
+ char szNum[32];
+
+# ifdef IN_RING3
+ /*
+ * Add the filename.
+ */
+ if (fDestFlags & RTLOGDEST_FILE)
+ {
+ rc = RTStrCopyP(&pszBuf, &cchBuf, fNotFirst ? " file=" : "file=");
+ if (RT_FAILURE(rc))
+ return rc;
+ rc = RTStrCopyP(&pszBuf, &cchBuf, pLogger->pInt->szFilename);
+ if (RT_FAILURE(rc))
+ return rc;
+ fNotFirst = true;
+
+ if (pLogger->pInt->cHistory)
+ {
+ RTStrPrintf(szNum, sizeof(szNum), fNotFirst ? " history=%u" : "history=%u", pLogger->pInt->cHistory);
+ rc = RTStrCopyP(&pszBuf, &cchBuf, szNum);
+ if (RT_FAILURE(rc))
+ return rc;
+ fNotFirst = true;
+ }
+ if (pLogger->pInt->cbHistoryFileMax != UINT64_MAX)
+ {
+ RTStrPrintf(szNum, sizeof(szNum), fNotFirst ? " histsize=%llu" : "histsize=%llu", pLogger->pInt->cbHistoryFileMax);
+ rc = RTStrCopyP(&pszBuf, &cchBuf, szNum);
+ if (RT_FAILURE(rc))
+ return rc;
+ fNotFirst = true;
+ }
+ if (pLogger->pInt->cSecsHistoryTimeSlot != UINT32_MAX)
+ {
+ RTStrPrintf(szNum, sizeof(szNum), fNotFirst ? " histtime=%llu" : "histtime=%llu", pLogger->pInt->cSecsHistoryTimeSlot);
+ rc = RTStrCopyP(&pszBuf, &cchBuf, szNum);
+ if (RT_FAILURE(rc))
+ return rc;
+ fNotFirst = true;
+ }
+ }
+# endif /* IN_RING3 */
+
+ /*
+ * Add the ring buffer.
+ */
+ if (fDestFlags & RTLOGDEST_RINGBUF)
+ {
+ if (pLogger->pInt->cbRingBuf == RTLOG_RINGBUF_DEFAULT_SIZE)
+ rc = RTStrCopyP(&pszBuf, &cchBuf, fNotFirst ? " ringbuf" : "ringbuf");
+ else
+ {
+ RTStrPrintf(szNum, sizeof(szNum), fNotFirst ? " ringbuf=%#x" : "ringbuf=%#x", pLogger->pInt->cbRingBuf);
+ rc = RTStrCopyP(&pszBuf, &cchBuf, szNum);
+ }
+ if (RT_FAILURE(rc))
+ return rc;
+ fNotFirst = true;
+ }
+
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTLogGetDestinations);
+
+#endif /* !IN_RC */
+
+/**
+ * Flushes the specified logger.
+ *
+ * @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(void) RTLogFlush(PRTLOGGER pLogger)
+{
+ /*
+ * Resolve defaults.
+ */
+ if (!pLogger)
+ {
+#ifdef IN_RC
+ pLogger = &g_Logger;
+#else
+ pLogger = g_pLogger;
+#endif
+ if (!pLogger)
+ return;
+ }
+
+ /*
+ * Any thing to flush?
+ */
+ if ( pLogger->offScratch
+#ifndef IN_RC
+ || (pLogger->fDestFlags & RTLOGDEST_RINGBUF)
+#endif
+ )
+ {
+#ifndef IN_RC
+ /*
+ * Acquire logger instance sem.
+ */
+ int rc = rtlogLock(pLogger);
+ if (RT_FAILURE(rc))
+ return;
+#endif
+ /*
+ * Call worker.
+ */
+ rtlogFlush(pLogger);
+
+#ifndef IN_RC
+ /*
+ * Since this is an explicit flush call, the ring buffer content should
+ * be flushed to the other destinations if active.
+ */
+ if ( (pLogger->fDestFlags & RTLOGDEST_RINGBUF)
+ && pLogger->pInt->pszRingBuf /* paranoia */)
+ rtLogRingBufFlush(pLogger);
+
+ /*
+ * Release the semaphore.
+ */
+ rtlogUnlock(pLogger);
+#endif
+ }
+}
+RT_EXPORT_SYMBOL(RTLogFlush);
+
+
+/**
+ * Common worker for RTLogDefaultInstance and RTLogDefaultInstanceEx.
+ */
+DECL_FORCE_INLINE(PRTLOGGER) rtLogDefaultInstanceCommon(void)
+{
+#ifdef IN_RC
+ return &g_Logger;
+
+#else /* !IN_RC */
+# ifdef IN_RING0
+ /*
+ * Check per thread loggers first.
+ */
+ if (g_cPerThreadLoggers)
+ {
+ const RTNATIVETHREAD Self = RTThreadNativeSelf();
+ int32_t i = RT_ELEMENTS(g_aPerThreadLoggers);
+ while (i-- > 0)
+ if (g_aPerThreadLoggers[i].NativeThread == Self)
+ return g_aPerThreadLoggers[i].pLogger;
+ }
+# endif /* IN_RING0 */
+
+ /*
+ * If no per thread logger, use the default one.
+ */
+ if (!g_pLogger)
+ g_pLogger = RTLogDefaultInit();
+ return g_pLogger;
+#endif /* !IN_RC */
+}
+
+
+RTDECL(PRTLOGGER) RTLogDefaultInstance(void)
+{
+ return rtLogDefaultInstanceCommon();
+}
+RT_EXPORT_SYMBOL(RTLogDefaultInstance);
+
+
+RTDECL(PRTLOGGER) RTLogDefaultInstanceEx(uint32_t fFlagsAndGroup)
+{
+ PRTLOGGER pLogger = rtLogDefaultInstanceCommon();
+ if (pLogger)
+ {
+ if (pLogger->fFlags & RTLOGFLAGS_DISABLED)
+ pLogger = NULL;
+ else
+ {
+ uint16_t const fFlags = RT_LO_U16(fFlagsAndGroup);
+ uint16_t const iGroup = RT_HI_U16(fFlagsAndGroup);
+ if ( iGroup != UINT16_MAX
+ && ( (pLogger->afGroups[iGroup < pLogger->cGroups ? iGroup : 0] & (fFlags | (uint32_t)RTLOGGRPFLAGS_ENABLED))
+ != (fFlags | (uint32_t)RTLOGGRPFLAGS_ENABLED)))
+ pLogger = NULL;
+ }
+ }
+ return pLogger;
+}
+RT_EXPORT_SYMBOL(RTLogDefaultInstanceEx);
+
+
+/**
+ * Common worker for RTLogGetDefaultInstance and RTLogGetDefaultInstanceEx.
+ */
+DECL_FORCE_INLINE(PRTLOGGER) rtLogGetDefaultInstanceCommon(void)
+{
+#ifdef IN_RC
+ return &g_Logger;
+#else
+# ifdef IN_RING0
+ /*
+ * Check per thread loggers first.
+ */
+ if (g_cPerThreadLoggers)
+ {
+ const RTNATIVETHREAD Self = RTThreadNativeSelf();
+ int32_t i = RT_ELEMENTS(g_aPerThreadLoggers);
+ while (i-- > 0)
+ if (g_aPerThreadLoggers[i].NativeThread == Self)
+ return g_aPerThreadLoggers[i].pLogger;
+ }
+# endif /* IN_RING0 */
+
+ return g_pLogger;
+#endif
+}
+
+
+RTDECL(PRTLOGGER) RTLogGetDefaultInstance(void)
+{
+ return rtLogGetDefaultInstanceCommon();
+}
+RT_EXPORT_SYMBOL(RTLogGetDefaultInstance);
+
+
+RTDECL(PRTLOGGER) RTLogGetDefaultInstanceEx(uint32_t fFlagsAndGroup)
+{
+ PRTLOGGER pLogger = rtLogGetDefaultInstanceCommon();
+ if (pLogger)
+ {
+ if (pLogger->fFlags & RTLOGFLAGS_DISABLED)
+ pLogger = NULL;
+ else
+ {
+ uint32_t const fFlags = RT_LO_U16(fFlagsAndGroup);
+ uint16_t const iGroup = RT_HI_U16(fFlagsAndGroup);
+ if ( iGroup != UINT16_MAX
+ && ( (pLogger->afGroups[iGroup < pLogger->cGroups ? iGroup : 0] & (fFlags | RTLOGGRPFLAGS_ENABLED))
+ != (fFlags | RTLOGGRPFLAGS_ENABLED)))
+ pLogger = NULL;
+ }
+ }
+ return pLogger;
+}
+RT_EXPORT_SYMBOL(RTLogGetDefaultInstanceEx);
+
+
+#ifndef IN_RC
+/**
+ * Sets the default logger instance.
+ *
+ * @returns iprt status code.
+ * @param pLogger The new default logger instance.
+ */
+RTDECL(PRTLOGGER) RTLogSetDefaultInstance(PRTLOGGER pLogger)
+{
+ return ASMAtomicXchgPtrT(&g_pLogger, pLogger, PRTLOGGER);
+}
+RT_EXPORT_SYMBOL(RTLogSetDefaultInstance);
+#endif /* !IN_RC */
+
+
+#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.
+ */
+RTDECL(int) RTLogSetDefaultInstanceThread(PRTLOGGER pLogger, uintptr_t uKey)
+{
+ int rc;
+ RTNATIVETHREAD Self = RTThreadNativeSelf();
+ if (pLogger)
+ {
+ int32_t i;
+ unsigned j;
+
+ AssertReturn(pLogger->u32Magic == RTLOGGER_MAGIC, VERR_INVALID_MAGIC);
+
+ /*
+ * Iterate the table to see if there is already an entry for this thread.
+ */
+ i = RT_ELEMENTS(g_aPerThreadLoggers);
+ while (i-- > 0)
+ if (g_aPerThreadLoggers[i].NativeThread == Self)
+ {
+ ASMAtomicWritePtr((void * volatile *)&g_aPerThreadLoggers[i].uKey, (void *)uKey);
+ g_aPerThreadLoggers[i].pLogger = pLogger;
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Allocate a new table entry.
+ */
+ i = ASMAtomicIncS32(&g_cPerThreadLoggers);
+ if (i > (int32_t)RT_ELEMENTS(g_aPerThreadLoggers))
+ {
+ ASMAtomicDecS32(&g_cPerThreadLoggers);
+ return VERR_BUFFER_OVERFLOW; /* horrible error code! */
+ }
+
+ for (j = 0; j < 10; j++)
+ {
+ i = RT_ELEMENTS(g_aPerThreadLoggers);
+ while (i-- > 0)
+ {
+ AssertCompile(sizeof(RTNATIVETHREAD) == sizeof(void*));
+ if ( g_aPerThreadLoggers[i].NativeThread == NIL_RTNATIVETHREAD
+ && ASMAtomicCmpXchgPtr((void * volatile *)&g_aPerThreadLoggers[i].NativeThread, (void *)Self, (void *)NIL_RTNATIVETHREAD))
+ {
+ ASMAtomicWritePtr((void * volatile *)&g_aPerThreadLoggers[i].uKey, (void *)uKey);
+ ASMAtomicWritePtr(&g_aPerThreadLoggers[i].pLogger, pLogger);
+ return VINF_SUCCESS;
+ }
+ }
+ }
+
+ ASMAtomicDecS32(&g_cPerThreadLoggers);
+ rc = VERR_INTERNAL_ERROR;
+ }
+ else
+ {
+ /*
+ * Search the array for the current thread.
+ */
+ int32_t i = RT_ELEMENTS(g_aPerThreadLoggers);
+ while (i-- > 0)
+ if ( g_aPerThreadLoggers[i].NativeThread == Self
+ || g_aPerThreadLoggers[i].uKey == uKey)
+ {
+ ASMAtomicWriteNullPtr((void * volatile *)&g_aPerThreadLoggers[i].uKey);
+ ASMAtomicWriteNullPtr(&g_aPerThreadLoggers[i].pLogger);
+ ASMAtomicWriteHandle(&g_aPerThreadLoggers[i].NativeThread, NIL_RTNATIVETHREAD);
+ ASMAtomicDecS32(&g_cPerThreadLoggers);
+ }
+
+ rc = VINF_SUCCESS;
+ }
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTLogSetDefaultInstanceThread);
+#endif /* IN_RING0 */
+
+
+/**
+ * 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)
+{
+ RTLogLoggerExV(pLogger, 0, ~0U, pszFormat, args);
+}
+RT_EXPORT_SYMBOL(RTLogLoggerV);
+
+
+/**
+ * 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 args Format arguments.
+ */
+RTDECL(void) RTLogLoggerExV(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, va_list args)
+{
+ int rc;
+
+ /*
+ * A NULL logger means default instance.
+ */
+ if (!pLogger)
+ {
+ pLogger = RTLogDefaultInstance();
+ if (!pLogger)
+ return;
+ }
+
+ /*
+ * Validate and correct iGroup.
+ */
+ if (iGroup != ~0U && iGroup >= pLogger->cGroups)
+ iGroup = 0;
+
+ /*
+ * If no output, then just skip it.
+ */
+ if ( (pLogger->fFlags & RTLOGFLAGS_DISABLED)
+#ifndef IN_RC
+ || !pLogger->fDestFlags
+#endif
+ || !pszFormat || !*pszFormat)
+ return;
+ if ( iGroup != ~0U
+ && (pLogger->afGroups[iGroup] & (fFlags | RTLOGGRPFLAGS_ENABLED)) != (fFlags | RTLOGGRPFLAGS_ENABLED))
+ return;
+
+ /*
+ * Acquire logger instance sem.
+ */
+ rc = rtlogLock(pLogger);
+ if (RT_FAILURE(rc))
+ {
+#ifdef IN_RING0
+ if (pLogger->fDestFlags & ~RTLOGDEST_FILE)
+ rtR0LogLoggerExFallback(pLogger->fDestFlags, pLogger->fFlags, pLogger->pInt, pszFormat, args);
+#endif
+ return;
+ }
+
+ /*
+ * Check restrictions and call worker.
+ */
+#ifndef IN_RC
+ if (RT_UNLIKELY( (pLogger->fFlags & RTLOGFLAGS_RESTRICT_GROUPS)
+ && iGroup < pLogger->cGroups
+ && (pLogger->afGroups[iGroup] & RTLOGGRPFLAGS_RESTRICT)
+ && ++pLogger->pInt->pacEntriesPerGroup[iGroup] >= pLogger->pInt->cMaxEntriesPerGroup ))
+ {
+ uint32_t cEntries = pLogger->pInt->pacEntriesPerGroup[iGroup];
+ if (cEntries > pLogger->pInt->cMaxEntriesPerGroup)
+ pLogger->pInt->pacEntriesPerGroup[iGroup] = cEntries - 1;
+ else
+ {
+ rtlogLoggerExVLocked(pLogger, fFlags, iGroup, pszFormat, args);
+ if ( pLogger->pInt->papszGroups
+ && pLogger->pInt->papszGroups[iGroup])
+ rtlogLoggerExFLocked(pLogger, fFlags, iGroup, "%u messages from group %s (#%u), muting it.\n",
+ cEntries, pLogger->pInt->papszGroups[iGroup], iGroup);
+ else
+ rtlogLoggerExFLocked(pLogger, fFlags, iGroup, "%u messages from group #%u, muting it.\n",
+ cEntries, iGroup);
+ }
+ }
+ else
+#endif
+ rtlogLoggerExVLocked(pLogger, fFlags, iGroup, pszFormat, args);
+
+ /*
+ * Release the semaphore.
+ */
+ rtlogUnlock(pLogger);
+}
+RT_EXPORT_SYMBOL(RTLogLoggerExV);
+
+
+#ifdef IN_RING0
+/**
+ * For rtR0LogLoggerExFallbackOutput and rtR0LogLoggerExFallbackFlush.
+ */
+typedef struct RTR0LOGLOGGERFALLBACK
+{
+ /** The current scratch buffer offset. */
+ uint32_t offScratch;
+ /** The destination flags. */
+ uint32_t fDestFlags;
+ /** For ring buffer output. */
+ PRTLOGGERINTERNAL pInt;
+ /** The scratch buffer. */
+ char achScratch[80];
+} RTR0LOGLOGGERFALLBACK;
+/** Pointer to RTR0LOGLOGGERFALLBACK which is used by
+ * rtR0LogLoggerExFallbackOutput. */
+typedef RTR0LOGLOGGERFALLBACK *PRTR0LOGLOGGERFALLBACK;
+
+
+/**
+ * Flushes the fallback buffer.
+ *
+ * @param pThis The scratch buffer.
+ */
+static void rtR0LogLoggerExFallbackFlush(PRTR0LOGLOGGERFALLBACK pThis)
+{
+ if (!pThis->offScratch)
+ return;
+
+ if ( (pThis->fDestFlags & RTLOGDEST_RINGBUF)
+ && pThis->pInt
+ && pThis->pInt->pszRingBuf /* paranoia */)
+ rtLogRingBufWrite(pThis->pInt, pThis->achScratch, pThis->offScratch);
+ else
+ {
+ if (pThis->fDestFlags & RTLOGDEST_USER)
+ RTLogWriteUser(pThis->achScratch, pThis->offScratch);
+
+ if (pThis->fDestFlags & RTLOGDEST_DEBUGGER)
+ RTLogWriteDebugger(pThis->achScratch, pThis->offScratch);
+
+ if (pThis->fDestFlags & RTLOGDEST_STDOUT)
+ RTLogWriteStdOut(pThis->achScratch, pThis->offScratch);
+
+ if (pThis->fDestFlags & RTLOGDEST_STDERR)
+ RTLogWriteStdErr(pThis->achScratch, pThis->offScratch);
+
+# ifndef LOG_NO_COM
+ if (pThis->fDestFlags & RTLOGDEST_COM)
+ RTLogWriteCom(pThis->achScratch, pThis->offScratch);
+# endif
+ }
+
+ /* empty the buffer. */
+ pThis->offScratch = 0;
+}
+
+
+/**
+ * Callback for RTLogFormatV used by rtR0LogLoggerExFallback.
+ * See PFNLOGOUTPUT() for details.
+ */
+static DECLCALLBACK(size_t) rtR0LogLoggerExFallbackOutput(void *pv, const char *pachChars, size_t cbChars)
+{
+ PRTR0LOGLOGGERFALLBACK pThis = (PRTR0LOGLOGGERFALLBACK)pv;
+ if (cbChars)
+ {
+ size_t cbRet = 0;
+ for (;;)
+ {
+ /* how much */
+ uint32_t cb = sizeof(pThis->achScratch) - pThis->offScratch - 1; /* minus 1 - for the string terminator. */
+ if (cb > cbChars)
+ cb = (uint32_t)cbChars;
+
+ /* copy */
+ memcpy(&pThis->achScratch[pThis->offScratch], pachChars, cb);
+
+ /* advance */
+ pThis->offScratch += cb;
+ cbRet += cb;
+ cbChars -= cb;
+
+ /* done? */
+ if (cbChars <= 0)
+ return cbRet;
+
+ pachChars += cb;
+
+ /* flush */
+ pThis->achScratch[pThis->offScratch] = '\0';
+ rtR0LogLoggerExFallbackFlush(pThis);
+ }
+
+ /* won't ever get here! */
+ }
+ else
+ {
+ /*
+ * Termination call, flush the log.
+ */
+ pThis->achScratch[pThis->offScratch] = '\0';
+ rtR0LogLoggerExFallbackFlush(pThis);
+ return 0;
+ }
+}
+
+
+/**
+ * Ring-0 fallback for cases where we're unable to grab the lock.
+ *
+ * This will happen when we're at a too high IRQL on Windows for instance and
+ * needs to be dealt with or we'll drop a lot of log output. This fallback will
+ * only output to some of the log destinations as a few of them may be doing
+ * dangerous things. We won't be doing any prefixing here either, at least not
+ * for the present, because it's too much hassle.
+ *
+ * @param fDestFlags The destination flags.
+ * @param fFlags The logger flags.
+ * @param pInt The internal logger data, for ring buffer output.
+ * @param pszFormat The format string.
+ * @param va The format arguments.
+ */
+static void rtR0LogLoggerExFallback(uint32_t fDestFlags, uint32_t fFlags, PRTLOGGERINTERNAL pInt,
+ const char *pszFormat, va_list va)
+{
+ RTR0LOGLOGGERFALLBACK This;
+ This.fDestFlags = fDestFlags;
+ This.pInt = pInt;
+
+ /* fallback indicator. */
+ This.offScratch = 2;
+ This.achScratch[0] = '[';
+ This.achScratch[1] = 'F';
+
+ /* selected prefixes */
+ if (fFlags & RTLOGFLAGS_PREFIX_PID)
+ {
+ RTPROCESS Process = RTProcSelf();
+ This.achScratch[This.offScratch++] = ' ';
+ This.offScratch += RTStrFormatNumber(&This.achScratch[This.offScratch], Process, 16, sizeof(RTPROCESS) * 2, 0, RTSTR_F_ZEROPAD);
+ }
+ if (fFlags & RTLOGFLAGS_PREFIX_TID)
+ {
+ RTNATIVETHREAD Thread = RTThreadNativeSelf();
+ This.achScratch[This.offScratch++] = ' ';
+ This.offScratch += RTStrFormatNumber(&This.achScratch[This.offScratch], Thread, 16, sizeof(RTNATIVETHREAD) * 2, 0, RTSTR_F_ZEROPAD);
+ }
+
+ This.achScratch[This.offScratch++] = ']';
+ This.achScratch[This.offScratch++] = ' ';
+
+ RTLogFormatV(rtR0LogLoggerExFallbackOutput, &This, pszFormat, va);
+}
+#endif /* IN_RING0 */
+
+
+/**
+ * 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)
+{
+ RTLogLoggerV(NULL, pszFormat, va);
+}
+RT_EXPORT_SYMBOL(RTLogPrintfV);
+
+
+/**
+ * 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)
+{
+ RTLogLoggerV((PRTLOGGER)pvUser, pszFormat, va);
+}
+RT_EXPORT_SYMBOL(RTLogDumpPrintfV);
+
+
+#ifdef IN_RING3
+
+/**
+ * Opens/creates the log file.
+ *
+ * @param pLogger The logger instance to update. NULL is not allowed!
+ * @param pszErrorMsg A buffer which is filled with an error message if
+ * something fails. May be NULL.
+ * @param cchErrorMsg The size of the error message buffer.
+ */
+static int rtlogFileOpen(PRTLOGGER pLogger, char *pszErrorMsg, size_t cchErrorMsg)
+{
+ uint32_t fOpen = RTFILE_O_WRITE | RTFILE_O_DENY_NONE;
+ if (pLogger->fFlags & RTLOGFLAGS_APPEND)
+ fOpen |= RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND;
+ else
+ fOpen |= RTFILE_O_CREATE_REPLACE;
+ if (pLogger->fFlags & RTLOGFLAGS_WRITE_THROUGH)
+ fOpen |= RTFILE_O_WRITE_THROUGH;
+
+ unsigned cBackoff = 0;
+ int rc = RTFileOpen(&pLogger->pInt->hFile, pLogger->pInt->szFilename, fOpen);
+ while ( rc == VERR_SHARING_VIOLATION
+ && cBackoff < RT_ELEMENTS(g_acMsLogBackoff))
+ {
+ RTThreadSleep(g_acMsLogBackoff[cBackoff++]);
+ rc = RTFileOpen(&pLogger->pInt->hFile, pLogger->pInt->szFilename, fOpen);
+ }
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTFileGetSize(pLogger->pInt->hFile, &pLogger->pInt->cbHistoryFileWritten);
+ if (RT_FAILURE(rc))
+ {
+ /* Don't complain if this fails, assume the file is empty. */
+ pLogger->pInt->cbHistoryFileWritten = 0;
+ rc = VINF_SUCCESS;
+ }
+ }
+ else
+ {
+ pLogger->pInt->hFile = NIL_RTFILE;
+ if (pszErrorMsg)
+ RTStrPrintf(pszErrorMsg, cchErrorMsg, N_("could not open file '%s' (fOpen=%#x)"), pLogger->pInt->szFilename, fOpen);
+ }
+ return rc;
+}
+
+
+/**
+ * Closes, rotates and opens the log files if necessary.
+ *
+ * Used by the rtlogFlush() function as well as RTLogCreateExV.
+ *
+ * @param pLogger The logger instance to update. NULL is not allowed!
+ * @param uTimeSlot Current time slot (for tikme based rotation).
+ * @param fFirst Flag whether this is the beginning of logging, i.e.
+ * called from RTLogCreateExV. Prevents pfnPhase from
+ * being called.
+ */
+static void rtlogRotate(PRTLOGGER pLogger, uint32_t uTimeSlot, bool fFirst)
+{
+ /* Suppress rotating empty log files simply because the time elapsed. */
+ if (RT_UNLIKELY(!pLogger->pInt->cbHistoryFileWritten))
+ pLogger->pInt->uHistoryTimeSlotStart = uTimeSlot;
+
+ /* Check rotation condition: file still small enough and not too old? */
+ if (RT_LIKELY( pLogger->pInt->cbHistoryFileWritten < pLogger->pInt->cbHistoryFileMax
+ && uTimeSlot == pLogger->pInt->uHistoryTimeSlotStart))
+ return;
+
+ /*
+ * Save "disabled" log flag and make sure logging is disabled.
+ * The logging in the functions called during log file history
+ * rotation would cause severe trouble otherwise.
+ */
+ uint32_t const fSavedFlags = pLogger->fFlags;
+ pLogger->fFlags |= RTLOGFLAGS_DISABLED;
+
+ /*
+ * Disable log rotation temporarily, otherwise with extreme settings and
+ * chatty phase logging we could run into endless rotation.
+ */
+ uint32_t const cSavedHistory = pLogger->pInt->cHistory;
+ pLogger->pInt->cHistory = 0;
+
+ /*
+ * Close the old log file.
+ */
+ if (pLogger->pInt->hFile != NIL_RTFILE)
+ {
+ /* Use the callback to generate some final log contents, but only if
+ * this is a rotation with a fully set up logger. Leave the other case
+ * to the RTLogCreateExV function. */
+ if (pLogger->pInt->pfnPhase && !fFirst)
+ {
+ uint32_t fODestFlags = pLogger->fDestFlags;
+ pLogger->fDestFlags &= RTLOGDEST_FILE;
+ pLogger->pInt->pfnPhase(pLogger, RTLOGPHASE_PREROTATE, rtlogPhaseMsgLocked);
+ pLogger->fDestFlags = fODestFlags;
+ }
+ RTFileClose(pLogger->pInt->hFile);
+ pLogger->pInt->hFile = NIL_RTFILE;
+ }
+
+ if (cSavedHistory)
+ {
+ /*
+ * Rotate the log files.
+ */
+ for (uint32_t i = cSavedHistory - 1; i + 1 > 0; i--)
+ {
+ char szOldName[sizeof(pLogger->pInt->szFilename) + 32];
+ if (i > 0)
+ RTStrPrintf(szOldName, sizeof(szOldName), "%s.%u", pLogger->pInt->szFilename, i);
+ else
+ RTStrCopy(szOldName, sizeof(szOldName), pLogger->pInt->szFilename);
+
+ char szNewName[sizeof(pLogger->pInt->szFilename) + 32];
+ RTStrPrintf(szNewName, sizeof(szNewName), "%s.%u", pLogger->pInt->szFilename, i + 1);
+
+ unsigned cBackoff = 0;
+ int rc = RTFileRename(szOldName, szNewName, RTFILEMOVE_FLAGS_REPLACE);
+ while ( rc == VERR_SHARING_VIOLATION
+ && cBackoff < RT_ELEMENTS(g_acMsLogBackoff))
+ {
+ RTThreadSleep(g_acMsLogBackoff[cBackoff++]);
+ rc = RTFileRename(szOldName, szNewName, RTFILEMOVE_FLAGS_REPLACE);
+ }
+
+ if (rc == VERR_FILE_NOT_FOUND)
+ RTFileDelete(szNewName);
+ }
+
+ /*
+ * Delete excess log files.
+ */
+ for (uint32_t i = cSavedHistory + 1; ; i++)
+ {
+ char szExcessName[sizeof(pLogger->pInt->szFilename) + 32];
+ RTStrPrintf(szExcessName, sizeof(szExcessName), "%s.%u", pLogger->pInt->szFilename, i);
+ int rc = RTFileDelete(szExcessName);
+ if (RT_FAILURE(rc))
+ break;
+ }
+ }
+
+ /*
+ * Update logger state and create new log file.
+ */
+ pLogger->pInt->cbHistoryFileWritten = 0;
+ pLogger->pInt->uHistoryTimeSlotStart = uTimeSlot;
+ rtlogFileOpen(pLogger, NULL, 0);
+
+ /*
+ * Use the callback to generate some initial log contents, but only if this
+ * is a rotation with a fully set up logger. Leave the other case to the
+ * RTLogCreateExV function.
+ */
+ if (pLogger->pInt->pfnPhase && !fFirst)
+ {
+ uint32_t const fSavedDestFlags = pLogger->fDestFlags;
+ pLogger->fDestFlags &= RTLOGDEST_FILE;
+ pLogger->pInt->pfnPhase(pLogger, RTLOGPHASE_POSTROTATE, rtlogPhaseMsgLocked);
+ pLogger->fDestFlags = fSavedDestFlags;
+ }
+
+ /* Restore saved values. */
+ pLogger->pInt->cHistory = cSavedHistory;
+ pLogger->fFlags = fSavedFlags;
+}
+
+#endif /* IN_RING3 */
+
+
+/**
+ * Writes the buffer to the given log device without checking for buffered
+ * data or anything.
+ * Used by the RTLogFlush() function.
+ *
+ * @param pLogger The logger instance to write to. NULL is not allowed!
+ */
+static void rtlogFlush(PRTLOGGER pLogger)
+{
+ uint32_t const cchScratch = pLogger->offScratch;
+ if (cchScratch == 0)
+ return; /* nothing to flush. */
+
+#ifndef IN_RC
+ /*
+ * If the ring buffer is active, the other destinations are only written
+ * to when the ring buffer is flushed by RTLogFlush().
+ */
+ if ( (pLogger->fDestFlags & RTLOGDEST_RINGBUF)
+ && pLogger->pInt
+ && pLogger->pInt->pszRingBuf /* paraoia */)
+ {
+ rtLogRingBufWrite(pLogger->pInt, pLogger->achScratch, pLogger->offScratch);
+ pLogger->offScratch = 0; /* empty the buffer. */
+ }
+ else
+#endif
+ {
+ /* Make sure the string is terminated. On Windows, RTLogWriteDebugger
+ will get upset if it isn't. */
+ if (RT_LIKELY(cchScratch < sizeof(pLogger->achScratch)))
+ pLogger->achScratch[cchScratch] = '\0';
+ else
+ AssertFailed();
+
+#ifndef IN_RC
+ if (pLogger->fDestFlags & RTLOGDEST_USER)
+ RTLogWriteUser(pLogger->achScratch, cchScratch);
+
+ if (pLogger->fDestFlags & RTLOGDEST_DEBUGGER)
+ RTLogWriteDebugger(pLogger->achScratch, cchScratch);
+
+# ifdef IN_RING3
+ if ((pLogger->fDestFlags & (RTLOGDEST_FILE | RTLOGDEST_RINGBUF)) == RTLOGDEST_FILE)
+ {
+ if (pLogger->pInt->hFile != NIL_RTFILE)
+ {
+ RTFileWrite(pLogger->pInt->hFile, pLogger->achScratch, cchScratch, NULL);
+ if (pLogger->fFlags & RTLOGFLAGS_FLUSH)
+ RTFileFlush(pLogger->pInt->hFile);
+ }
+ if (pLogger->pInt->cHistory)
+ pLogger->pInt->cbHistoryFileWritten += cchScratch;
+ }
+# endif
+
+ if (pLogger->fDestFlags & RTLOGDEST_STDOUT)
+ RTLogWriteStdOut(pLogger->achScratch, cchScratch);
+
+ if (pLogger->fDestFlags & RTLOGDEST_STDERR)
+ RTLogWriteStdErr(pLogger->achScratch, cchScratch);
+
+# if (defined(IN_RING0) || defined(IN_RC)) && !defined(LOG_NO_COM)
+ if (pLogger->fDestFlags & RTLOGDEST_COM)
+ RTLogWriteCom(pLogger->achScratch, cchScratch);
+# endif
+#endif /* !IN_RC */
+
+#ifdef IN_RC
+ if (pLogger->pfnFlush)
+ pLogger->pfnFlush(pLogger);
+#else
+ if (pLogger->pInt->pfnFlush)
+ pLogger->pInt->pfnFlush(pLogger);
+#endif
+
+ /* empty the buffer. */
+ pLogger->offScratch = 0;
+
+#ifdef IN_RING3
+ /*
+ * Rotate the log file if configured. Must be done after everything is
+ * flushed, since this will also use logging/flushing to write the header
+ * and footer messages.
+ */
+ if ( (pLogger->fDestFlags & RTLOGDEST_FILE)
+ && pLogger->pInt->cHistory)
+ rtlogRotate(pLogger, RTTimeProgramSecTS() / pLogger->pInt->cSecsHistoryTimeSlot, false /* fFirst */);
+#endif
+ }
+}
+
+
+/**
+ * Callback for RTLogFormatV which writes to the com port.
+ * See PFNLOGOUTPUT() for details.
+ */
+static DECLCALLBACK(size_t) rtLogOutput(void *pv, const char *pachChars, size_t cbChars)
+{
+ PRTLOGGER pLogger = (PRTLOGGER)pv;
+ if (cbChars)
+ {
+ size_t cbRet = 0;
+ for (;;)
+ {
+#if defined(DEBUG) && defined(IN_RING3)
+ /* sanity */
+ if (pLogger->offScratch >= sizeof(pLogger->achScratch))
+ {
+ fprintf(stderr, "pLogger->offScratch >= sizeof(pLogger->achScratch) (%#x >= %#x)\n",
+ pLogger->offScratch, (unsigned)sizeof(pLogger->achScratch));
+ AssertBreakpoint(); AssertBreakpoint();
+ }
+#endif
+
+ /* how much */
+ size_t cb = sizeof(pLogger->achScratch) - pLogger->offScratch - 1;
+ if (cb > cbChars)
+ cb = cbChars;
+
+ /* copy */
+ memcpy(&pLogger->achScratch[pLogger->offScratch], pachChars, cb);
+
+ /* advance */
+ pLogger->offScratch += (uint32_t)cb;
+ cbRet += cb;
+ cbChars -= cb;
+
+ /* done? */
+ if (cbChars <= 0)
+ return cbRet;
+
+ pachChars += cb;
+
+ /* flush */
+ rtlogFlush(pLogger);
+ }
+
+ /* won't ever get here! */
+ }
+ else
+ {
+ /*
+ * Termination call.
+ * There's always space for a terminator, and it's not counted.
+ */
+ pLogger->achScratch[pLogger->offScratch] = '\0';
+ return 0;
+ }
+}
+
+
+/**
+ * stpncpy implementation for use in rtLogOutputPrefixed w/ padding.
+ *
+ * @returns Pointer to the destination buffer byte following the copied string.
+ * @param pszDst The destination buffer.
+ * @param pszSrc The source string.
+ * @param cchSrcMax The maximum number of characters to copy from
+ * the string.
+ * @param cchMinWidth The minimum field with, padd with spaces to
+ * reach this.
+ */
+DECLINLINE(char *) rtLogStPNCpyPad(char *pszDst, const char *pszSrc, size_t cchSrcMax, size_t cchMinWidth)
+{
+ size_t cchSrc = 0;
+ if (pszSrc)
+ {
+ cchSrc = strlen(pszSrc);
+ if (cchSrc > cchSrcMax)
+ cchSrc = cchSrcMax;
+
+ memcpy(pszDst, pszSrc, cchSrc);
+ pszDst += cchSrc;
+ }
+ do
+ *pszDst++ = ' ';
+ while (cchSrc++ < cchMinWidth);
+
+ return pszDst;
+}
+
+
+
+/**
+ * Callback for RTLogFormatV which writes to the logger instance.
+ * This version supports prefixes.
+ *
+ * See PFNLOGOUTPUT() for details.
+ */
+static DECLCALLBACK(size_t) rtLogOutputPrefixed(void *pv, const char *pachChars, size_t cbChars)
+{
+ PRTLOGOUTPUTPREFIXEDARGS pArgs = (PRTLOGOUTPUTPREFIXEDARGS)pv;
+ PRTLOGGER pLogger = pArgs->pLogger;
+ if (cbChars)
+ {
+ size_t cbRet = 0;
+ for (;;)
+ {
+ size_t cb = sizeof(pLogger->achScratch) - pLogger->offScratch - 1;
+ const char *pszNewLine;
+ char *psz;
+#ifdef IN_RC
+ bool *pfPendingPrefix = &pLogger->fPendingPrefix;
+#else
+ bool *pfPendingPrefix = &pLogger->pInt->fPendingPrefix;
+#endif
+
+ /*
+ * Pending prefix?
+ */
+ if (*pfPendingPrefix)
+ {
+ *pfPendingPrefix = false;
+
+#if defined(DEBUG) && defined(IN_RING3)
+ /* sanity */
+ if (pLogger->offScratch >= sizeof(pLogger->achScratch))
+ {
+ fprintf(stderr, "pLogger->offScratch >= sizeof(pLogger->achScratch) (%#x >= %#x)\n",
+ pLogger->offScratch, (unsigned)sizeof(pLogger->achScratch));
+ AssertBreakpoint(); AssertBreakpoint();
+ }
+#endif
+
+ /*
+ * Flush the buffer if there isn't enough room for the maximum prefix config.
+ * Max is 256, add a couple of extra bytes. See CCH_PREFIX check way below.
+ */
+ if (cb < 256 + 16)
+ {
+ rtlogFlush(pLogger);
+ cb = sizeof(pLogger->achScratch) - pLogger->offScratch - 1;
+ }
+
+ /*
+ * Write the prefixes.
+ * psz is pointing to the current position.
+ */
+ psz = &pLogger->achScratch[pLogger->offScratch];
+ if (pLogger->fFlags & RTLOGFLAGS_PREFIX_TS)
+ {
+ uint64_t u64 = RTTimeNanoTS();
+ int iBase = 16;
+ unsigned int fFlags = RTSTR_F_ZEROPAD;
+ if (pLogger->fFlags & RTLOGFLAGS_DECIMAL_TS)
+ {
+ iBase = 10;
+ fFlags = 0;
+ }
+ if (pLogger->fFlags & RTLOGFLAGS_REL_TS)
+ {
+ static volatile uint64_t s_u64LastTs;
+ uint64_t u64DiffTs = u64 - s_u64LastTs;
+ s_u64LastTs = u64;
+ /* We could have been preempted just before reading of s_u64LastTs by
+ * another thread which wrote s_u64LastTs. In that case the difference
+ * is negative which we simply ignore. */
+ u64 = (int64_t)u64DiffTs < 0 ? 0 : u64DiffTs;
+ }
+ /* 1E15 nanoseconds = 11 days */
+ psz += RTStrFormatNumber(psz, u64, iBase, 16, 0, fFlags);
+ *psz++ = ' ';
+ }
+#define CCH_PREFIX_01 0 + 17
+
+ if (pLogger->fFlags & RTLOGFLAGS_PREFIX_TSC)
+ {
+#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
+ uint64_t u64 = ASMReadTSC();
+#else
+ uint64_t u64 = RTTimeNanoTS();
+#endif
+ int iBase = 16;
+ unsigned int fFlags = RTSTR_F_ZEROPAD;
+ if (pLogger->fFlags & RTLOGFLAGS_DECIMAL_TS)
+ {
+ iBase = 10;
+ fFlags = 0;
+ }
+ if (pLogger->fFlags & RTLOGFLAGS_REL_TS)
+ {
+ static volatile uint64_t s_u64LastTsc;
+ int64_t i64DiffTsc = u64 - s_u64LastTsc;
+ s_u64LastTsc = u64;
+ /* We could have been preempted just before reading of s_u64LastTsc by
+ * another thread which wrote s_u64LastTsc. In that case the difference
+ * is negative which we simply ignore. */
+ u64 = i64DiffTsc < 0 ? 0 : i64DiffTsc;
+ }
+ /* 1E15 ticks at 4GHz = 69 hours */
+ psz += RTStrFormatNumber(psz, u64, iBase, 16, 0, fFlags);
+ *psz++ = ' ';
+ }
+#define CCH_PREFIX_02 CCH_PREFIX_01 + 17
+
+ if (pLogger->fFlags & RTLOGFLAGS_PREFIX_MS_PROG)
+ {
+#if defined(IN_RING3) || defined(IN_RC)
+ uint64_t u64 = RTTimeProgramMilliTS();
+#else
+ uint64_t u64 = 0;
+#endif
+ /* 1E8 milliseconds = 27 hours */
+ psz += RTStrFormatNumber(psz, u64, 10, 9, 0, RTSTR_F_ZEROPAD);
+ *psz++ = ' ';
+ }
+#define CCH_PREFIX_03 CCH_PREFIX_02 + 21
+
+ if (pLogger->fFlags & RTLOGFLAGS_PREFIX_TIME)
+ {
+#if defined(IN_RING3) || defined(IN_RING0)
+ RTTIMESPEC TimeSpec;
+ RTTIME Time;
+ RTTimeExplode(&Time, RTTimeNow(&TimeSpec));
+ psz += RTStrFormatNumber(psz, Time.u8Hour, 10, 2, 0, RTSTR_F_ZEROPAD);
+ *psz++ = ':';
+ psz += RTStrFormatNumber(psz, Time.u8Minute, 10, 2, 0, RTSTR_F_ZEROPAD);
+ *psz++ = ':';
+ psz += RTStrFormatNumber(psz, Time.u8Second, 10, 2, 0, RTSTR_F_ZEROPAD);
+ *psz++ = '.';
+ psz += RTStrFormatNumber(psz, Time.u32Nanosecond / 1000, 10, 6, 0, RTSTR_F_ZEROPAD);
+ *psz++ = ' ';
+#else
+ memset(psz, ' ', 16);
+ psz += 16;
+#endif
+ }
+#define CCH_PREFIX_04 CCH_PREFIX_03 + (3+1+3+1+3+1+7+1)
+
+ if (pLogger->fFlags & RTLOGFLAGS_PREFIX_TIME_PROG)
+ {
+
+#if defined(IN_RING3) || defined(IN_RC)
+ uint64_t u64 = RTTimeProgramMicroTS();
+ psz += RTStrFormatNumber(psz, (uint32_t)(u64 / RT_US_1HOUR), 10, 2, 0, RTSTR_F_ZEROPAD);
+ *psz++ = ':';
+ uint32_t u32 = (uint32_t)(u64 % RT_US_1HOUR);
+ psz += RTStrFormatNumber(psz, u32 / RT_US_1MIN, 10, 2, 0, RTSTR_F_ZEROPAD);
+ *psz++ = ':';
+ u32 %= RT_US_1MIN;
+
+ psz += RTStrFormatNumber(psz, u32 / RT_US_1SEC, 10, 2, 0, RTSTR_F_ZEROPAD);
+ *psz++ = '.';
+ psz += RTStrFormatNumber(psz, u32 % RT_US_1SEC, 10, 6, 0, RTSTR_F_ZEROPAD);
+ *psz++ = ' ';
+#else
+ memset(psz, ' ', 16);
+ psz += 16;
+#endif
+ }
+#define CCH_PREFIX_05 CCH_PREFIX_04 + (9+1+2+1+2+1+6+1)
+
+# if 0
+ if (pLogger->fFlags & RTLOGFLAGS_PREFIX_DATETIME)
+ {
+ char szDate[32];
+ RTTIMESPEC Time;
+ RTTimeSpecToString(RTTimeNow(&Time), szDate, sizeof(szDate));
+ size_t cch = strlen(szDate);
+ memcpy(psz, szDate, cch);
+ psz += cch;
+ *psz++ = ' ';
+ }
+# define CCH_PREFIX_06 CCH_PREFIX_05 + 32
+# else
+# define CCH_PREFIX_06 CCH_PREFIX_05 + 0
+# endif
+
+ if (pLogger->fFlags & RTLOGFLAGS_PREFIX_PID)
+ {
+#ifndef IN_RC
+ RTPROCESS Process = RTProcSelf();
+#else
+ RTPROCESS Process = NIL_RTPROCESS;
+#endif
+ psz += RTStrFormatNumber(psz, Process, 16, sizeof(RTPROCESS) * 2, 0, RTSTR_F_ZEROPAD);
+ *psz++ = ' ';
+ }
+#define CCH_PREFIX_07 CCH_PREFIX_06 + 9
+
+ if (pLogger->fFlags & RTLOGFLAGS_PREFIX_TID)
+ {
+#ifndef IN_RC
+ RTNATIVETHREAD Thread = RTThreadNativeSelf();
+#else
+ RTNATIVETHREAD Thread = NIL_RTNATIVETHREAD;
+#endif
+ psz += RTStrFormatNumber(psz, Thread, 16, sizeof(RTNATIVETHREAD) * 2, 0, RTSTR_F_ZEROPAD);
+ *psz++ = ' ';
+ }
+#define CCH_PREFIX_08 CCH_PREFIX_07 + 17
+
+ if (pLogger->fFlags & RTLOGFLAGS_PREFIX_THREAD)
+ {
+#ifdef IN_RING3
+ const char *pszName = RTThreadSelfName();
+#elif defined IN_RC
+ const char *pszName = "EMT-RC";
+#else
+ const char *pszName = "R0";
+#endif
+ psz = rtLogStPNCpyPad(psz, pszName, 16, 8);
+ }
+#define CCH_PREFIX_09 CCH_PREFIX_08 + 17
+
+ if (pLogger->fFlags & RTLOGFLAGS_PREFIX_CPUID)
+ {
+#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
+ const uint8_t idCpu = ASMGetApicId();
+#else
+ const RTCPUID idCpu = RTMpCpuId();
+#endif
+ psz += RTStrFormatNumber(psz, idCpu, 16, sizeof(idCpu) * 2, 0, RTSTR_F_ZEROPAD);
+ *psz++ = ' ';
+ }
+#define CCH_PREFIX_10 CCH_PREFIX_09 + 17
+
+#ifndef IN_RC
+ if ( (pLogger->fFlags & RTLOGFLAGS_PREFIX_CUSTOM)
+ && pLogger->pInt->pfnPrefix)
+ {
+ psz += pLogger->pInt->pfnPrefix(pLogger, psz, 31, pLogger->pInt->pvPrefixUserArg);
+ *psz++ = ' '; /* +32 */
+ }
+#endif
+#define CCH_PREFIX_11 CCH_PREFIX_10 + 32
+
+ if (pLogger->fFlags & RTLOGFLAGS_PREFIX_LOCK_COUNTS)
+ {
+#ifdef IN_RING3 /** @todo implement these counters in ring-0 too? */
+ RTTHREAD Thread = RTThreadSelf();
+ if (Thread != NIL_RTTHREAD)
+ {
+ uint32_t cReadLocks = RTLockValidatorReadLockGetCount(Thread);
+ uint32_t cWriteLocks = RTLockValidatorWriteLockGetCount(Thread) - g_cLoggerLockCount;
+ cReadLocks = RT_MIN(0xfff, cReadLocks);
+ cWriteLocks = RT_MIN(0xfff, cWriteLocks);
+ psz += RTStrFormatNumber(psz, cReadLocks, 16, 1, 0, RTSTR_F_ZEROPAD);
+ *psz++ = '/';
+ psz += RTStrFormatNumber(psz, cWriteLocks, 16, 1, 0, RTSTR_F_ZEROPAD);
+ }
+ else
+#endif
+ {
+ *psz++ = '?';
+ *psz++ = '/';
+ *psz++ = '?';
+ }
+ *psz++ = ' ';
+ }
+#define CCH_PREFIX_12 CCH_PREFIX_11 + 8
+
+ if (pLogger->fFlags & RTLOGFLAGS_PREFIX_FLAG_NO)
+ {
+ psz += RTStrFormatNumber(psz, pArgs->fFlags, 16, 8, 0, RTSTR_F_ZEROPAD);
+ *psz++ = ' ';
+ }
+#define CCH_PREFIX_13 CCH_PREFIX_12 + 9
+
+ if (pLogger->fFlags & RTLOGFLAGS_PREFIX_FLAG)
+ {
+#ifdef IN_RING3
+ const char *pszGroup = pArgs->iGroup != ~0U ? pLogger->pInt->papszGroups[pArgs->iGroup] : NULL;
+#else
+ const char *pszGroup = NULL;
+#endif
+ psz = rtLogStPNCpyPad(psz, pszGroup, 16, 8);
+ }
+#define CCH_PREFIX_14 CCH_PREFIX_13 + 17
+
+ if (pLogger->fFlags & RTLOGFLAGS_PREFIX_GROUP_NO)
+ {
+ if (pArgs->iGroup != ~0U)
+ {
+ psz += RTStrFormatNumber(psz, pArgs->iGroup, 16, 3, 0, RTSTR_F_ZEROPAD);
+ *psz++ = ' ';
+ }
+ else
+ {
+ memcpy(psz, "-1 ", sizeof("-1 ") - 1);
+ psz += sizeof("-1 ") - 1;
+ } /* +9 */
+ }
+#define CCH_PREFIX_15 CCH_PREFIX_14 + 9
+
+ if (pLogger->fFlags & RTLOGFLAGS_PREFIX_GROUP)
+ {
+ const unsigned fGrp = pLogger->afGroups[pArgs->iGroup != ~0U ? pArgs->iGroup : 0];
+ const char *pszGroup;
+ size_t cch;
+ switch (pArgs->fFlags & fGrp)
+ {
+ case 0: pszGroup = "--------"; cch = sizeof("--------") - 1; break;
+ case RTLOGGRPFLAGS_ENABLED: pszGroup = "enabled" ; cch = sizeof("enabled" ) - 1; break;
+ case RTLOGGRPFLAGS_LEVEL_1: pszGroup = "level 1" ; cch = sizeof("level 1" ) - 1; break;
+ case RTLOGGRPFLAGS_LEVEL_2: pszGroup = "level 2" ; cch = sizeof("level 2" ) - 1; break;
+ case RTLOGGRPFLAGS_LEVEL_3: pszGroup = "level 3" ; cch = sizeof("level 3" ) - 1; break;
+ case RTLOGGRPFLAGS_LEVEL_4: pszGroup = "level 4" ; cch = sizeof("level 4" ) - 1; break;
+ case RTLOGGRPFLAGS_LEVEL_5: pszGroup = "level 5" ; cch = sizeof("level 5" ) - 1; break;
+ case RTLOGGRPFLAGS_LEVEL_6: pszGroup = "level 6" ; cch = sizeof("level 6" ) - 1; break;
+ case RTLOGGRPFLAGS_LEVEL_7: pszGroup = "level 7" ; cch = sizeof("level 7" ) - 1; break;
+ case RTLOGGRPFLAGS_LEVEL_8: pszGroup = "level 8" ; cch = sizeof("level 8" ) - 1; break;
+ case RTLOGGRPFLAGS_LEVEL_9: pszGroup = "level 9" ; cch = sizeof("level 9" ) - 1; break;
+ case RTLOGGRPFLAGS_LEVEL_10: pszGroup = "level 10"; cch = sizeof("level 10") - 1; break;
+ case RTLOGGRPFLAGS_LEVEL_11: pszGroup = "level 11"; cch = sizeof("level 11") - 1; break;
+ case RTLOGGRPFLAGS_LEVEL_12: pszGroup = "level 12"; cch = sizeof("level 12") - 1; break;
+ case RTLOGGRPFLAGS_FLOW: pszGroup = "flow" ; cch = sizeof("flow" ) - 1; break;
+ case RTLOGGRPFLAGS_WARN: pszGroup = "warn" ; cch = sizeof("warn" ) - 1; break;
+ default: pszGroup = "????????"; cch = sizeof("????????") - 1; break;
+ }
+ psz = rtLogStPNCpyPad(psz, pszGroup, 16, 8);
+ }
+#define CCH_PREFIX_16 CCH_PREFIX_15 + 17
+
+#define CCH_PREFIX ( CCH_PREFIX_16 )
+ { AssertCompile(CCH_PREFIX < 256); }
+
+ /*
+ * Done, figure what we've used and advance the buffer and free size.
+ */
+ cb = psz - &pLogger->achScratch[pLogger->offScratch];
+ AssertMsg(cb <= 223, ("%#zx (%zd) - fFlags=%#x\n", cb, cb, pLogger->fFlags));
+ pLogger->offScratch += (uint32_t)cb;
+ cb = sizeof(pLogger->achScratch) - pLogger->offScratch - 1;
+ }
+ else if (cb <= 0)
+ {
+ rtlogFlush(pLogger);
+ cb = sizeof(pLogger->achScratch) - pLogger->offScratch - 1;
+ }
+
+#if defined(DEBUG) && defined(IN_RING3)
+ /* sanity */
+ if (pLogger->offScratch >= sizeof(pLogger->achScratch))
+ {
+ fprintf(stderr, "pLogger->offScratch >= sizeof(pLogger->achScratch) (%#x >= %#x)\n",
+ pLogger->offScratch, (unsigned)sizeof(pLogger->achScratch));
+ AssertBreakpoint(); AssertBreakpoint();
+ }
+#endif
+
+ /* how much */
+ if (cb > cbChars)
+ cb = cbChars;
+
+ /* have newline? */
+ pszNewLine = (const char *)memchr(pachChars, '\n', cb);
+ if (pszNewLine)
+ {
+ if (pLogger->fFlags & RTLOGFLAGS_USECRLF)
+ cb = pszNewLine - pachChars;
+ else
+ {
+ cb = pszNewLine - pachChars + 1;
+ *pfPendingPrefix = true;
+ }
+ }
+
+ /* copy */
+ memcpy(&pLogger->achScratch[pLogger->offScratch], pachChars, cb);
+
+ /* advance */
+ pLogger->offScratch += (uint32_t)cb;
+ cbRet += cb;
+ cbChars -= cb;
+
+ if ( pszNewLine
+ && (pLogger->fFlags & RTLOGFLAGS_USECRLF)
+ && pLogger->offScratch + 2 < sizeof(pLogger->achScratch))
+ {
+ memcpy(&pLogger->achScratch[pLogger->offScratch], "\r\n", 2);
+ pLogger->offScratch += 2;
+ cbRet++;
+ cbChars--;
+ cb++;
+ *pfPendingPrefix = true;
+ }
+
+ /* done? */
+ if (cbChars <= 0)
+ return cbRet;
+ pachChars += cb;
+ }
+
+ /* won't ever get here! */
+ }
+ else
+ {
+ /*
+ * Termination call.
+ * There's always space for a terminator, and it's not counted.
+ */
+ pLogger->achScratch[pLogger->offScratch] = '\0';
+ return 0;
+ }
+}
+
+
+/**
+ * Write to a logger instance (worker function).
+ *
+ * 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. Must be non-NULL.
+ * @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.
+ */
+static void rtlogLoggerExVLocked(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, va_list args)
+{
+ /*
+ * Format the message and perhaps flush it.
+ */
+ if (pLogger->fFlags & (RTLOGFLAGS_PREFIX_MASK | RTLOGFLAGS_USECRLF))
+ {
+ RTLOGOUTPUTPREFIXEDARGS OutputArgs;
+ OutputArgs.pLogger = pLogger;
+ OutputArgs.iGroup = iGroup;
+ OutputArgs.fFlags = fFlags;
+ RTLogFormatV(rtLogOutputPrefixed, &OutputArgs, pszFormat, args);
+ }
+ else
+ RTLogFormatV(rtLogOutput, pLogger, pszFormat, args);
+ if ( !(pLogger->fFlags & RTLOGFLAGS_BUFFERED)
+ && pLogger->offScratch)
+ rtlogFlush(pLogger);
+}
+
+
+#ifndef IN_RC
+/**
+ * For calling rtlogLoggerExVLocked.
+ *
+ * @param pLogger The logger.
+ * @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.
+ */
+static void rtlogLoggerExFLocked(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, ...)
+{
+ va_list va;
+ va_start(va, pszFormat);
+ rtlogLoggerExVLocked(pLogger, fFlags, iGroup, pszFormat, va);
+ va_end(va);
+}
+#endif /* !IN_RC */
+
--- /dev/null
+/* $Id: logcom.cpp $ */
+/** @file
+ * IPRT - Logging to Serial Port.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+#ifndef IPRT_UART_BASE
+/** The port address of the COM port to log to.
+ *
+ * To override the default (COM1) append IPRT_UART_BASE=0xWXYZ to DEFS in your
+ * LocalConfig.kmk. Alternatively you can edit this file, but the don't forget
+ * to also update the default found in VBox/asmdefs.h.
+ *
+ * Standard port assignments are: COM1=0x3f8, COM2=0x2f8, COM3=0x3e8, COM4=0x2e8.
+ */
+# define IPRT_UART_BASE 0x3f8
+#endif
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/log.h>
+#include "internal/iprt.h"
+
+#include <iprt/asm.h>
+#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) /** @todo consider fixing the config instead. */
+# include <iprt/asm-amd64-x86.h>
+#endif
+#include <iprt/stdarg.h>
+#include <iprt/string.h>
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+static DECLCALLBACK(size_t) rtLogComOutput(void *pv, const char *pachChars, size_t cbChars);
+
+
+/**
+ * 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, ...)
+{
+ va_list args;
+ size_t cb;
+ va_start(args, pszFormat);
+ cb = RTLogComPrintfV(pszFormat, args);
+ va_end(args);
+
+ return cb;
+}
+RT_EXPORT_SYMBOL(RTLogComPrintf);
+
+
+/**
+ * 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)
+{
+ return RTLogFormatV(rtLogComOutput, NULL, pszFormat, args);
+}
+RT_EXPORT_SYMBOL(RTLogComPrintfV);
+
+
+/**
+ * Callback for RTLogFormatV which writes to the com port.
+ * See PFNLOGOUTPUT() for details.
+ */
+static DECLCALLBACK(size_t) rtLogComOutput(void *pv, const char *pachChars, size_t cbChars)
+{
+ NOREF(pv);
+ if (cbChars)
+ RTLogWriteCom(pachChars, cbChars);
+ return cbChars;
+}
+
+
+/**
+ * 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)
+{
+#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
+ const uint8_t *pu8;
+ for (pu8 = (const uint8_t *)pach; cb-- > 0; pu8++)
+ {
+ register unsigned cMaxWait;
+ register uint8_t u8;
+
+ /* expand \n -> \r\n */
+ if (*pu8 == '\n')
+ RTLogWriteCom("\r", 1);
+
+ /* Check if port is ready. */
+ cMaxWait = ~0U;
+ do
+ {
+ u8 = ASMInU8(IPRT_UART_BASE + 5);
+ cMaxWait--;
+ } while (!(u8 & 0x20) && u8 != 0xff && cMaxWait);
+
+ /* write */
+ ASMOutU8(IPRT_UART_BASE, *pu8);
+ }
+#else
+ /* PORTME? */
+#endif
+}
+RT_EXPORT_SYMBOL(RTLogWriteCom);
+
--- /dev/null
+/* $Id: logellipsis.cpp $ */
+/** @file
+ * Runtime VBox - Logger, the ellipsis variants.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/log.h>
+#include "internal/iprt.h"
+
+#include <iprt/asm.h>
+#include <iprt/stdarg.h>
+
+
+/**
+ * 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, ...)
+{
+ va_list args;
+ va_start(args, pszFormat);
+#if defined(RT_OS_DARWIN) && defined(RT_ARCH_X86) && defined(IN_RING3)
+ /* manually align the stack before doing the call.
+ * We boldly assume that there is a stack frame here! */
+ __asm__ __volatile__("andl $-32, %%esp\t\n" ::: "%esp");
+ RTLogLoggerExV(pLogger, 0, ~0U, pszFormat, args);
+#else
+ RTLogLoggerExV(pLogger, 0, ~0U, pszFormat, args);
+#endif
+ va_end(args);
+ NOREF(pvCallerRet);
+}
+RT_EXPORT_SYMBOL(RTLogLogger);
+
+
+/**
+ * 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, ...)
+{
+ va_list args;
+ va_start(args, pszFormat);
+ RTLogLoggerExV(pLogger, fFlags, iGroup, pszFormat, args);
+ va_end(args);
+}
+RT_EXPORT_SYMBOL(RTLogLoggerEx);
+
+
+/**
+ * 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, ...)
+{
+ va_list args;
+ va_start(args, pszFormat);
+ RTLogPrintfV(pszFormat, args);
+ va_end(args);
+}
+RT_EXPORT_SYMBOL(RTLogPrintf);
+
--- /dev/null
+/* $Id: logformat.cpp $ */
+/** @file
+ * IPRT - Log Formatter.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/log.h>
+#include "internal/iprt.h"
+
+#include <iprt/string.h>
+#include <iprt/assert.h>
+#ifdef IN_RING3
+# include <iprt/thread.h>
+# include <iprt/err.h>
+#endif
+
+#include <iprt/stdarg.h>
+#include <iprt/string.h>
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+static DECLCALLBACK(size_t) rtlogFormatStr(void *pvArg, PFNRTSTROUTPUT pfnOutput,
+ void *pvArgOutput, const char **ppszFormat,
+ va_list *pArgs, int cchWidth, int cchPrecision,
+ unsigned fFlags, char chArgSize);
+
+
+/**
+ * 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)
+{
+ return RTStrFormatV(pfnOutput, pvArg, rtlogFormatStr, NULL, pszFormat, args);
+}
+RT_EXPORT_SYMBOL(RTLogFormatV);
+
+
+/**
+ * Callback to format VBox formatting extentions.
+ * See @ref pg_rt_str_format for a reference on the format types.
+ *
+ * @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'.
+ */
+static DECLCALLBACK(size_t) rtlogFormatStr(void *pvArg, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
+ const char **ppszFormat, va_list *pArgs, int cchWidth,
+ int cchPrecision, unsigned fFlags, char chArgSize)
+{
+ char ch = *(*ppszFormat)++;
+
+ AssertMsgFailed(("Invalid logger format type '%%%c%.10s'!\n", ch, *ppszFormat)); NOREF(ch);
+
+ NOREF(pvArg); NOREF(pfnOutput); NOREF(pvArgOutput); NOREF(pArgs); NOREF(cchWidth);
+ NOREF(cchPrecision); NOREF(fFlags); NOREF(chArgSize);
+ return 0;
+}
+
--- /dev/null
+/* $Id: logrel.cpp $ */
+/** @file
+ * Runtime VBox - Release Logger.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/log.h>
+#include "internal/iprt.h"
+
+#ifndef IN_RC
+# include <iprt/alloc.h>
+# include <iprt/process.h>
+# include <iprt/semaphore.h>
+# include <iprt/thread.h>
+# include <iprt/mp.h>
+#endif
+#ifdef IN_RING3
+# include <iprt/file.h>
+# include <iprt/path.h>
+#endif
+#include <iprt/time.h>
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/param.h>
+
+#include <iprt/stdarg.h>
+#include <iprt/string.h>
+#include <iprt/ctype.h>
+#ifdef IN_RING3
+# include <iprt/alloca.h>
+# include <stdio.h>
+#endif
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+#ifdef IN_RC
+/** Default release logger instance. */
+extern "C" DECLIMPORT(RTLOGGERRC) g_RelLogger;
+#else /* !IN_RC */
+/** Default release logger instance. */
+static PRTLOGGER g_pRelLogger;
+#endif /* !IN_RC */
+
+
+RTDECL(PRTLOGGER) RTLogRelGetDefaultInstance(void)
+{
+#ifdef IN_RC
+ return &g_RelLogger;
+#else /* !IN_RC */
+ return g_pRelLogger;
+#endif /* !IN_RC */
+}
+RT_EXPORT_SYMBOL(RTLogRelGetDefaultInstance);
+
+
+RTDECL(PRTLOGGER) RTLogRelGetDefaultInstanceEx(uint32_t fFlagsAndGroup)
+{
+#ifdef IN_RC
+ PRTLOGGER pLogger = &g_RelLogger;
+#else /* !IN_RC */
+ PRTLOGGER pLogger = g_pRelLogger;
+#endif /* !IN_RC */
+ if (pLogger)
+ {
+ if (pLogger->fFlags & RTLOGFLAGS_DISABLED)
+ pLogger = NULL;
+ else
+ {
+ uint16_t const fFlags = RT_LO_U16(fFlagsAndGroup);
+ uint16_t const iGroup = RT_HI_U16(fFlagsAndGroup);
+ if ( iGroup != UINT16_MAX
+ && ( (pLogger->afGroups[iGroup < pLogger->cGroups ? iGroup : 0] & (fFlags | (uint32_t)RTLOGGRPFLAGS_ENABLED))
+ != (fFlags | (uint32_t)RTLOGGRPFLAGS_ENABLED)))
+ pLogger = NULL;
+ }
+ }
+ return pLogger;
+}
+RT_EXPORT_SYMBOL(RTLogRelGetDefaultInstanceEx);
+
+
+#ifndef IN_RC
+/**
+ * Sets the default logger instance.
+ *
+ * @returns iprt status code.
+ * @param pLogger The new default release logger instance.
+ */
+RTDECL(PRTLOGGER) RTLogRelSetDefaultInstance(PRTLOGGER pLogger)
+{
+ return ASMAtomicXchgPtrT(&g_pRelLogger, pLogger, PRTLOGGER);
+}
+RT_EXPORT_SYMBOL(RTLogRelSetDefaultInstance);
+#endif /* !IN_RC */
+
+
+/**
+ * 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)
+{
+ /*
+ * A NULL logger means default instance.
+ */
+ if (!pLogger)
+ {
+ pLogger = RTLogRelGetDefaultInstance();
+ if (!pLogger)
+ return;
+ }
+ RTLogLoggerExV(pLogger, fFlags, iGroup, pszFormat, args);
+}
+RT_EXPORT_SYMBOL(RTLogRelLoggerV);
+
+
+/**
+ * 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)
+{
+ RTLogRelLoggerV(NULL, 0, ~0U, pszFormat, args);
+}
+RT_EXPORT_SYMBOL(RTLogRelPrintfV);
+
+
+/**
+ * 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)
+{
+ PRTLOGGER pLogger = RTLogRelGetDefaultInstance();
+ if (pLogger)
+ return RTLogSetBuffering(pLogger, fBuffered);
+ return false;
+}
+RT_EXPORT_SYMBOL(RTLogRelSetBuffering);
+
--- /dev/null
+/* $Id: logrelellipsis.cpp $ */
+/** @file
+ * Runtime VBox - Logger, the release ellipsis variants.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/log.h>
+#include "internal/iprt.h"
+
+#include <iprt/stdarg.h>
+
+
+/**
+ * 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, ...)
+{
+ va_list args;
+ va_start(args, pszFormat);
+ RTLogRelLoggerV(pLogger, fFlags, iGroup, pszFormat, args);
+ va_end(args);
+}
+RT_EXPORT_SYMBOL(RTLogRelLogger);
+
+
+/**
+ * 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, ...)
+{
+ va_list args;
+ va_start(args, pszFormat);
+ RTLogRelPrintfV(pszFormat, args);
+ va_end(args);
+}
+RT_EXPORT_SYMBOL(RTLogRelPrintf);
+
--- /dev/null
+/* $NetBSD: divdi3.c,v 1.8 2005/12/11 12:24:37 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+/*#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)divdi3.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: divdi3.c,v 1.8 2005/12/11 12:24:37 christos Exp $");
+#endif
+#endif*/ /* LIBC_SCCS and not lint */
+
+#include "quad.h"
+
+/*
+ * Divide two signed quads.
+ * ??? if -1/2 should produce -1 on this machine, this code is wrong
+ */
+quad_t
+__divdi3(a, b)
+ quad_t a, b;
+{
+ u_quad_t ua, ub, uq;
+ int neg = 0;
+
+ ua = a;
+ ub = b;
+
+ if (a < 0)
+ ua = -ua, neg ^= 1;
+ if (b < 0)
+ ub = -ub, neg ^= 1;
+
+ uq = __qdivrem(ua, ub, (u_quad_t *)0);
+ if (neg)
+ uq = - uq;
+ return uq;
+}
--- /dev/null
+/* $NetBSD: moddi3.c,v 1.8 2005/12/11 12:24:37 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+/*#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)moddi3.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: moddi3.c,v 1.8 2005/12/11 12:24:37 christos Exp $");
+#endif
+#endif*/ /* LIBC_SCCS and not lint */
+
+#include "quad.h"
+
+/*
+ * Return remainder after dividing two signed quads.
+ *
+ * XXX we assume a % b < 0 iff a < 0, but this is actually machine-dependent.
+ */
+quad_t
+__moddi3(a, b)
+ quad_t a, b;
+{
+ u_quad_t ua, ub, ur;
+ int neg = 0;
+
+ ua = a;
+ ub = b;
+
+ if (a < 0)
+ ua = -ua, neg ^= 1;
+ if (b < 0)
+ ub = -ub;
+ (void)__qdivrem(ua, ub, &ur);
+ if (neg)
+ ur = -ur;
+ return (ur);
+}
--- /dev/null
+/* $NetBSD: qdivrem.c,v 1.12 2005/12/11 12:24:37 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+/*#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)qdivrem.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: qdivrem.c,v 1.12 2005/12/11 12:24:37 christos Exp $");
+#endif
+#endif*/ /* LIBC_SCCS and not lint */
+
+/*
+ * Multiprecision divide. This algorithm is from Knuth vol. 2 (2nd ed),
+ * section 4.3.1, pp. 257--259.
+ */
+
+#include "quad.h"
+
+#define B ((int)1 << HALF_BITS) /* digit base */
+
+/* Combine two `digits' to make a single two-digit number. */
+#define COMBINE(a, b) (((u_int)(a) << HALF_BITS) | (b))
+
+/* select a type for digits in base B: use unsigned short if they fit */
+#if UINT_MAX == 0xffffffffU && USHRT_MAX >= 0xffff
+typedef unsigned short digit;
+#else
+typedef u_int digit;
+#endif
+
+static void shl __P((digit *p, int len, int sh));
+
+/*
+ * __qdivrem(u, v, rem) returns u/v and, optionally, sets *rem to u%v.
+ *
+ * We do this in base 2-sup-HALF_BITS, so that all intermediate products
+ * fit within u_int. As a consequence, the maximum length dividend and
+ * divisor are 4 `digits' in this base (they are shorter if they have
+ * leading zeros).
+ */
+u_quad_t
+__qdivrem(uq, vq, arq)
+ u_quad_t uq, vq, *arq;
+{
+ union uu tmp;
+ digit *u, *v, *q;
+ digit v1, v2;
+ u_int qhat, rhat, t;
+ int m, n, d, j, i;
+ digit uspace[5], vspace[5], qspace[5];
+
+ /*
+ * Take care of special cases: divide by zero, and u < v.
+ */
+ if (vq == 0) {
+ /* divide by zero. */
+ static volatile const unsigned int zero = 0;
+
+ tmp.ul[H] = tmp.ul[L] = 1 / zero;
+ if (arq)
+ *arq = uq;
+ return (tmp.q);
+ }
+ if (uq < vq) {
+ if (arq)
+ *arq = uq;
+ return (0);
+ }
+ u = &uspace[0];
+ v = &vspace[0];
+ q = &qspace[0];
+
+ /*
+ * Break dividend and divisor into digits in base B, then
+ * count leading zeros to determine m and n. When done, we
+ * will have:
+ * u = (u[1]u[2]...u[m+n]) sub B
+ * v = (v[1]v[2]...v[n]) sub B
+ * v[1] != 0
+ * 1 < n <= 4 (if n = 1, we use a different division algorithm)
+ * m >= 0 (otherwise u < v, which we already checked)
+ * m + n = 4
+ * and thus
+ * m = 4 - n <= 2
+ */
+ tmp.uq = uq;
+ u[0] = 0;
+ u[1] = (digit)HHALF(tmp.ul[H]);
+ u[2] = (digit)LHALF(tmp.ul[H]);
+ u[3] = (digit)HHALF(tmp.ul[L]);
+ u[4] = (digit)LHALF(tmp.ul[L]);
+ tmp.uq = vq;
+ v[1] = (digit)HHALF(tmp.ul[H]);
+ v[2] = (digit)LHALF(tmp.ul[H]);
+ v[3] = (digit)HHALF(tmp.ul[L]);
+ v[4] = (digit)LHALF(tmp.ul[L]);
+ for (n = 4; v[1] == 0; v++) {
+ if (--n == 1) {
+ u_int rbj; /* r*B+u[j] (not root boy jim) */
+ digit q1, q2, q3, q4;
+
+ /*
+ * Change of plan, per exercise 16.
+ * r = 0;
+ * for j = 1..4:
+ * q[j] = floor((r*B + u[j]) / v),
+ * r = (r*B + u[j]) % v;
+ * We unroll this completely here.
+ */
+ t = v[2]; /* nonzero, by definition */
+ q1 = (digit)(u[1] / t);
+ rbj = COMBINE(u[1] % t, u[2]);
+ q2 = (digit)(rbj / t);
+ rbj = COMBINE(rbj % t, u[3]);
+ q3 = (digit)(rbj / t);
+ rbj = COMBINE(rbj % t, u[4]);
+ q4 = (digit)(rbj / t);
+ if (arq)
+ *arq = rbj % t;
+ tmp.ul[H] = COMBINE(q1, q2);
+ tmp.ul[L] = COMBINE(q3, q4);
+ return (tmp.q);
+ }
+ }
+
+ /*
+ * By adjusting q once we determine m, we can guarantee that
+ * there is a complete four-digit quotient at &qspace[1] when
+ * we finally stop.
+ */
+ for (m = 4 - n; u[1] == 0; u++)
+ m--;
+ for (i = 4 - m; --i >= 0;)
+ q[i] = 0;
+ q += 4 - m;
+
+ /*
+ * Here we run Program D, translated from MIX to C and acquiring
+ * a few minor changes.
+ *
+ * D1: choose multiplier 1 << d to ensure v[1] >= B/2.
+ */
+ d = 0;
+ for (t = v[1]; t < B / 2; t <<= 1)
+ d++;
+ if (d > 0) {
+ shl(&u[0], m + n, d); /* u <<= d */
+ shl(&v[1], n - 1, d); /* v <<= d */
+ }
+ /*
+ * D2: j = 0.
+ */
+ j = 0;
+ v1 = v[1]; /* for D3 -- note that v[1..n] are constant */
+ v2 = v[2]; /* for D3 */
+ do {
+ digit uj0, uj1, uj2;
+
+ /*
+ * D3: Calculate qhat (\^q, in TeX notation).
+ * Let qhat = min((u[j]*B + u[j+1])/v[1], B-1), and
+ * let rhat = (u[j]*B + u[j+1]) mod v[1].
+ * While rhat < B and v[2]*qhat > rhat*B+u[j+2],
+ * decrement qhat and increase rhat correspondingly.
+ * Note that if rhat >= B, v[2]*qhat < rhat*B.
+ */
+ uj0 = u[j + 0]; /* for D3 only -- note that u[j+...] change */
+ uj1 = u[j + 1]; /* for D3 only */
+ uj2 = u[j + 2]; /* for D3 only */
+ if (uj0 == v1) {
+ qhat = B;
+ rhat = uj1;
+ goto qhat_too_big;
+ } else {
+ u_int nn = COMBINE(uj0, uj1);
+ qhat = nn / v1;
+ rhat = nn % v1;
+ }
+ while (v2 * qhat > COMBINE(rhat, uj2)) {
+ qhat_too_big:
+ qhat--;
+ if ((rhat += v1) >= B)
+ break;
+ }
+ /*
+ * D4: Multiply and subtract.
+ * The variable `t' holds any borrows across the loop.
+ * We split this up so that we do not require v[0] = 0,
+ * and to eliminate a final special case.
+ */
+ for (t = 0, i = n; i > 0; i--) {
+ t = u[i + j] - v[i] * qhat - t;
+ u[i + j] = (digit)LHALF(t);
+ t = (B - HHALF(t)) & (B - 1);
+ }
+ t = u[j] - t;
+ u[j] = (digit)LHALF(t);
+ /*
+ * D5: test remainder.
+ * There is a borrow if and only if HHALF(t) is nonzero;
+ * in that (rare) case, qhat was too large (by exactly 1).
+ * Fix it by adding v[1..n] to u[j..j+n].
+ */
+ if (HHALF(t)) {
+ qhat--;
+ for (t = 0, i = n; i > 0; i--) { /* D6: add back. */
+ t += u[i + j] + v[i];
+ u[i + j] = (digit)LHALF(t);
+ t = HHALF(t);
+ }
+ u[j] = (digit)LHALF(u[j] + t);
+ }
+ q[j] = (digit)qhat;
+ } while (++j <= m); /* D7: loop on j. */
+
+ /*
+ * If caller wants the remainder, we have to calculate it as
+ * u[m..m+n] >> d (this is at most n digits and thus fits in
+ * u[m+1..m+n], but we may need more source digits).
+ */
+ if (arq) {
+ if (d) {
+ for (i = m + n; i > m; --i)
+ u[i] = (digit)(((u_int)u[i] >> d) |
+ LHALF((u_int)u[i - 1] << (HALF_BITS - d)));
+ u[i] = 0;
+ }
+ tmp.ul[H] = COMBINE(uspace[1], uspace[2]);
+ tmp.ul[L] = COMBINE(uspace[3], uspace[4]);
+ *arq = tmp.q;
+ }
+
+ tmp.ul[H] = COMBINE(qspace[1], qspace[2]);
+ tmp.ul[L] = COMBINE(qspace[3], qspace[4]);
+ return (tmp.q);
+}
+
+/*
+ * Shift p[0]..p[len] left `sh' bits, ignoring any bits that
+ * `fall out' the left (there never will be any such anyway).
+ * We may assume len >= 0. NOTE THAT THIS WRITES len+1 DIGITS.
+ */
+static void
+shl(digit *p, int len, int sh)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ p[i] = (digit)(LHALF((u_int)p[i] << sh) |
+ ((u_int)p[i + 1] >> (HALF_BITS - sh)));
+ p[i] = (digit)(LHALF((u_int)p[i] << sh));
+}
--- /dev/null
+/* $NetBSD: quad.h,v 1.17 2005/12/11 12:24:37 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ * @(#)quad.h 8.1 (Berkeley) 6/4/93
+ */
+
+/*
+ * Quad arithmetic.
+ *
+ * This library makes the following assumptions:
+ *
+ * - The type long long (aka quad_t) exists.
+ *
+ * - A quad variable is exactly twice as long as `int'.
+ *
+ * - The machine's arithmetic is two's complement.
+ *
+ * This library can provide 128-bit arithmetic on a machine with 128-bit
+ * quads and 64-bit ints, for instance, or 96-bit arithmetic on machines
+ * with 48-bit ints.
+ */
+
+#if 0 /* iprt */
+#include <sys/types.h>
+#if !defined(_KERNEL) && !defined(_STANDALONE)
+#include <limits.h>
+#else
+#include <machine/limits.h>
+#endif
+#else /* iprt */
+# include <iprt/types.h>
+# include <iprt/nocrt/limits.h>
+# undef __P
+# define __P(a) a
+# undef __GNUC_PREREQ__
+# define __GNUC_PREREQ__(m1,m2) 1
+# if 1 /* ASSUMES: little endian */
+# define _QUAD_HIGHWORD 1
+# define _QUAD_LOWWORD 0
+# else
+# define _QUAD_HIGHWORD 0
+# define _QUAD_LOWWORD 1
+# endif
+# if !defined(RT_OS_LINUX) || !defined(__KERNEL__) /* (linux/types.h defines u_int) */
+ typedef unsigned int u_int;
+# endif
+# if !defined(RT_OS_SOLARIS)
+ typedef int64_t quad_t;
+# else
+# define quad_t int64_t
+# endif
+ typedef uint64_t u_quad_t;
+ typedef quad_t *qaddr_t;
+#endif /* iprt */
+
+/*
+ * Depending on the desired operation, we view a `long long' (aka quad_t) in
+ * one or more of the following formats.
+ */
+union uu {
+ quad_t q; /* as a (signed) quad */
+ u_quad_t uq; /* as an unsigned quad */
+ int sl[2]; /* as two signed ints */
+ u_int ul[2]; /* as two unsigned ints */
+};
+
+/*
+ * Define high and low parts of a quad_t.
+ */
+#define H _QUAD_HIGHWORD
+#define L _QUAD_LOWWORD
+
+/*
+ * Total number of bits in a quad_t and in the pieces that make it up.
+ * These are used for shifting, and also below for halfword extraction
+ * and assembly.
+ */
+#define QUAD_BITS (sizeof(quad_t) * CHAR_BIT)
+#define INT_BITS (sizeof(int) * CHAR_BIT)
+#define HALF_BITS (sizeof(int) * CHAR_BIT / 2)
+
+/*
+ * Extract high and low shortwords from longword, and move low shortword of
+ * longword to upper half of long, i.e., produce the upper longword of
+ * ((quad_t)(x) << (number_of_bits_in_int/2)). (`x' must actually be u_int.)
+ *
+ * These are used in the multiply code, to split a longword into upper
+ * and lower halves, and to reassemble a product as a quad_t, shifted left
+ * (sizeof(int)*CHAR_BIT/2).
+ */
+#define HHALF(x) ((u_int)(x) >> HALF_BITS)
+#define LHALF(x) ((u_int)(x) & (((int)1 << HALF_BITS) - 1))
+#define LHUP(x) ((u_int)(x) << HALF_BITS)
+
+/*
+ * XXX
+ * Compensate for gcc 1 vs gcc 2. Gcc 1 defines ?sh?di3's second argument
+ * as u_quad_t, while gcc 2 correctly uses int. Unfortunately, we still use
+ * both compilers.
+ */
+#if __GNUC_PREREQ__(2, 0) || defined(lint)
+typedef unsigned int qshift_t;
+#else
+typedef u_quad_t qshift_t;
+#endif
+
+RT_C_DECLS_BEGIN
+quad_t __adddi3 __P((quad_t, quad_t));
+quad_t __anddi3 __P((quad_t, quad_t));
+quad_t __ashldi3 __P((quad_t, qshift_t));
+quad_t __ashrdi3 __P((quad_t, qshift_t));
+int __cmpdi2 __P((quad_t, quad_t ));
+quad_t __divdi3 __P((quad_t, quad_t));
+quad_t __fixdfdi __P((double));
+quad_t __fixsfdi __P((float));
+u_quad_t __fixunsdfdi __P((double));
+u_quad_t __fixunssfdi __P((float));
+double __floatdidf __P((quad_t));
+float __floatdisf __P((quad_t));
+double __floatunsdidf __P((u_quad_t));
+quad_t __iordi3 __P((quad_t, quad_t));
+quad_t __lshldi3 __P((quad_t, qshift_t));
+quad_t __lshrdi3 __P((quad_t, qshift_t));
+quad_t __moddi3 __P((quad_t, quad_t));
+quad_t __muldi3 __P((quad_t, quad_t));
+quad_t __negdi2 __P((quad_t));
+quad_t __one_cmpldi2 __P((quad_t));
+u_quad_t __qdivrem __P((u_quad_t, u_quad_t, u_quad_t *));
+quad_t __subdi3 __P((quad_t, quad_t));
+int __ucmpdi2 __P((u_quad_t, u_quad_t));
+u_quad_t __udivdi3 __P((u_quad_t, u_quad_t ));
+u_quad_t __umoddi3 __P((u_quad_t, u_quad_t ));
+quad_t __xordi3 __P((quad_t, quad_t));
+RT_C_DECLS_END
--- /dev/null
+/* $NetBSD: udivdi3.c,v 1.8 2005/12/11 12:24:37 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+/*#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)udivdi3.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: udivdi3.c,v 1.8 2005/12/11 12:24:37 christos Exp $");
+#endif
+#endif*/ /* LIBC_SCCS and not lint */
+
+#include "quad.h"
+
+/*
+ * Divide two unsigned quads.
+ */
+u_quad_t
+__udivdi3(a, b)
+ u_quad_t a, b;
+{
+
+ return (__qdivrem(a, b, (u_quad_t *)0));
+}
--- /dev/null
+/* $Id: udivmoddi4.c $ */
+/** @file
+ * IPRT - __udivmoddi4 implementation
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#include <iprt/stdint.h>
+#include <iprt/uint64.h>
+
+uint64_t __udivmoddi4(uint64_t u64A, uint64_t u64B, uint64_t *pu64R);
+
+/**
+ * __udivmoddi4() implementation to satisfy external references from 32-bit
+ * code generated by gcc-7 or later.
+ *
+ * @param u64A The divident value.
+ * @param u64B The divisor value.
+ * @param pu64R A pointer to the reminder. May be NULL.
+ * @returns u64A / u64B
+ */
+uint64_t __udivmoddi4(uint64_t u64A, uint64_t u64B, uint64_t *pu64R)
+{
+ RTUINT64U Divident;
+ RTUINT64U Divisor;
+ RTUINT64U Quotient;
+ RTUINT64U Reminder;
+ Divident.u = u64A;
+ Divisor.u = u64B;
+ RTUInt64DivRem(&Quotient, &Reminder, &Divident, &Divisor);
+ if (pu64R)
+ *pu64R = Reminder.u;
+ return Quotient.u;
+}
--- /dev/null
+/* $NetBSD: umoddi3.c,v 1.8 2005/12/11 12:24:37 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+/*#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)umoddi3.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: umoddi3.c,v 1.8 2005/12/11 12:24:37 christos Exp $");
+#endif
+#endif*/ /* LIBC_SCCS and not lint */
+
+#include "quad.h"
+
+/*
+ * Return remainder after dividing two unsigned quads.
+ */
+u_quad_t
+__umoddi3(a, b)
+ u_quad_t a, b;
+{
+ u_quad_t r;
+
+ (void)__qdivrem(a, b, &r);
+ return (r);
+}
--- /dev/null
+/* $Id: RTAssertMsg1Weak.cpp $ */
+/** @file
+ * IPRT - RTAssertMsg1Weak.
+ */
+
+/*
+ * Copyright (C) 2008-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/assert.h>
+#include "internal/iprt.h"
+
+#include <iprt/stdarg.h>
+
+
+RTDECL(void) RTAssertMsg1Weak(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction)
+{
+ RTAssertMsg1(pszExpr, uLine, pszFile, pszFunction);
+}
+RT_EXPORT_SYMBOL(RTAssertMsg1Weak);
+
--- /dev/null
+/* $Id: RTAssertMsg2.cpp $ */
+/** @file
+ * IPRT - RTAssertMsg2.
+ */
+
+/*
+ * Copyright (C) 2008-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/assert.h>
+#include "internal/iprt.h"
+
+#include <iprt/stdarg.h>
+
+
+RTDECL(void) RTAssertMsg2(const char *pszFormat, ...)
+{
+ va_list va;
+ va_start(va, pszFormat);
+ RTAssertMsg2V(pszFormat, va);
+ va_end(va);
+}
+RT_EXPORT_SYMBOL(RTAssertMsg2);
+
--- /dev/null
+/* $Id: RTAssertMsg2Add.cpp $ */
+/** @file
+ * IPRT - RTAssertMsg2Add.
+ */
+
+/*
+ * Copyright (C) 2008-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/assert.h>
+#include "internal/iprt.h"
+
+#include <iprt/stdarg.h>
+
+
+RTDECL(void) RTAssertMsg2Add(const char *pszFormat, ...)
+{
+ va_list va;
+ va_start(va, pszFormat);
+ RTAssertMsg2AddV(pszFormat, va);
+ va_end(va);
+}
+RT_EXPORT_SYMBOL(RTAssertMsg2Add);
+
--- /dev/null
+/* $Id: RTAssertMsg2AddWeak.cpp $ */
+/** @file
+ * IPRT - RTAssertMsg2AddWeak.
+ */
+
+/*
+ * Copyright (C) 2008-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/assert.h>
+#include "internal/iprt.h"
+
+#include <iprt/stdarg.h>
+
+
+RTDECL(void) RTAssertMsg2AddWeak(const char *pszFormat, ...)
+{
+ va_list va;
+ va_start(va, pszFormat);
+ RTAssertMsg2AddWeakV(pszFormat, va);
+ va_end(va);
+}
+RT_EXPORT_SYMBOL(RTAssertMsg2AddWeak);
+
--- /dev/null
+/* $Id: RTAssertMsg2AddWeakV.cpp $ */
+/** @file
+ * IPRT - RTAssertMsg2AddWeakV.
+ */
+
+/*
+ * Copyright (C) 2009-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/assert.h>
+#include "internal/iprt.h"
+
+
+RTDECL(void) RTAssertMsg2AddWeakV(const char *pszFormat, va_list va)
+{
+ RTAssertMsg2AddV(pszFormat, va);
+}
+RT_EXPORT_SYMBOL(RTAssertMsg2AddWeakV);
+
--- /dev/null
+/* $Id: RTAssertMsg2Weak.cpp $ */
+/** @file
+ * IPRT - RTAssertMsg2Weak.
+ */
+
+/*
+ * Copyright (C) 2008-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/assert.h>
+#include "internal/iprt.h"
+
+#include <iprt/stdarg.h>
+
+
+RTDECL(void) RTAssertMsg2Weak(const char *pszFormat, ...)
+{
+ va_list va;
+ va_start(va, pszFormat);
+ RTAssertMsg2WeakV(pszFormat, va);
+ va_end(va);
+}
+RT_EXPORT_SYMBOL(RTAssertMsg2Weak);
+
--- /dev/null
+/* $Id: RTAssertMsg2WeakV.cpp $ */
+/** @file
+ * IPRT - RTAssertMsg2WeakV.
+ */
+
+/*
+ * Copyright (C) 2009-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/assert.h>
+#include "internal/iprt.h"
+
+
+RTDECL(void) RTAssertMsg2WeakV(const char *pszFormat, va_list va)
+{
+ RTAssertMsg2V(pszFormat, va);
+}
+RT_EXPORT_SYMBOL(RTAssertMsg2WeakV);
+
--- /dev/null
+/* $Id: assert.cpp $ */
+/** @file
+ * IPRT - Assertions, common code.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/assert.h>
+#include "internal/iprt.h"
+
+#include <iprt/asm.h>
+#include <iprt/err.h>
+#include <iprt/log.h>
+#include <iprt/string.h>
+#include <iprt/stdarg.h>
+#ifdef IN_RING3
+# include <stdio.h>
+#endif
+#include "internal/assert.h"
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/** The last assert message, 1st part. */
+RTDATADECL(char) g_szRTAssertMsg1[1024];
+RT_EXPORT_SYMBOL(g_szRTAssertMsg1);
+/** The last assert message, 2nd part. */
+RTDATADECL(char) g_szRTAssertMsg2[4096];
+RT_EXPORT_SYMBOL(g_szRTAssertMsg2);
+/** The length of the g_szRTAssertMsg2 content.
+ * @remarks Race. */
+static uint32_t volatile g_cchRTAssertMsg2;
+/** The last assert message, expression. */
+RTDATADECL(const char * volatile) g_pszRTAssertExpr;
+RT_EXPORT_SYMBOL(g_pszRTAssertExpr);
+/** The last assert message, function name. */
+RTDATADECL(const char * volatile) g_pszRTAssertFunction;
+RT_EXPORT_SYMBOL(g_pszRTAssertFunction);
+/** The last assert message, file name. */
+RTDATADECL(const char * volatile) g_pszRTAssertFile;
+RT_EXPORT_SYMBOL(g_pszRTAssertFile);
+/** The last assert message, line number. */
+RTDATADECL(uint32_t volatile) g_u32RTAssertLine;
+RT_EXPORT_SYMBOL(g_u32RTAssertLine);
+
+
+/** Set if assertions are quiet. */
+static bool volatile g_fQuiet = false;
+/** Set if assertions may panic. */
+static bool volatile g_fMayPanic = true;
+
+
+RTDECL(bool) RTAssertSetQuiet(bool fQuiet)
+{
+ return ASMAtomicXchgBool(&g_fQuiet, fQuiet);
+}
+RT_EXPORT_SYMBOL(RTAssertSetQuiet);
+
+
+RTDECL(bool) RTAssertAreQuiet(void)
+{
+ return ASMAtomicUoReadBool(&g_fQuiet);
+}
+RT_EXPORT_SYMBOL(RTAssertAreQuiet);
+
+
+RTDECL(bool) RTAssertSetMayPanic(bool fMayPanic)
+{
+ return ASMAtomicXchgBool(&g_fMayPanic, fMayPanic);
+}
+RT_EXPORT_SYMBOL(RTAssertSetMayPanic);
+
+
+RTDECL(bool) RTAssertMayPanic(void)
+{
+ return ASMAtomicUoReadBool(&g_fMayPanic);
+}
+RT_EXPORT_SYMBOL(RTAssertMayPanic);
+
+
+RTDECL(void) RTAssertMsg1(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction)
+{
+ /*
+ * Fill in the globals.
+ */
+ ASMAtomicUoWritePtr(&g_pszRTAssertExpr, pszExpr);
+ ASMAtomicUoWritePtr(&g_pszRTAssertFile, pszFile);
+ ASMAtomicUoWritePtr(&g_pszRTAssertFunction, pszFunction);
+ ASMAtomicUoWriteU32(&g_u32RTAssertLine, uLine);
+ RTStrPrintf(g_szRTAssertMsg1, sizeof(g_szRTAssertMsg1),
+ "\n!!Assertion Failed!!\n"
+ "Expression: %s\n"
+ "Location : %s(%d) %s\n",
+ pszExpr, pszFile, uLine, pszFunction);
+
+ /*
+ * If not quiet, make noise.
+ */
+ if (!RTAssertAreQuiet())
+ {
+ RTERRVARS SavedErrVars;
+ RTErrVarsSave(&SavedErrVars);
+
+#ifdef IN_RING0
+# ifdef IN_GUEST_R0
+ RTLogBackdoorPrintf("\n!!Assertion Failed!!\n"
+ "Expression: %s\n"
+ "Location : %s(%d) %s\n",
+ pszExpr, pszFile, uLine, pszFunction);
+# endif
+ /** @todo fully integrate this with the logger... play safe a bit for now. */
+ rtR0AssertNativeMsg1(pszExpr, uLine, pszFile, pszFunction);
+
+#else /* !IN_RING0 */
+# if !defined(IN_RING3) && !defined(LOG_NO_COM)
+# if 0 /* Enable this iff you have a COM port and really want this debug info. */
+ RTLogComPrintf("\n!!Assertion Failed!!\n"
+ "Expression: %s\n"
+ "Location : %s(%d) %s\n",
+ pszExpr, pszFile, uLine, pszFunction);
+# endif
+# endif
+
+ PRTLOGGER pLog = RTLogRelGetDefaultInstance();
+ if (pLog)
+ {
+ RTLogRelPrintf("\n!!Assertion Failed!!\n"
+ "Expression: %s\n"
+ "Location : %s(%d) %s\n",
+ pszExpr, pszFile, uLine, pszFunction);
+# ifndef IN_RC /* flushing is done automatically in RC */
+ RTLogFlush(pLog);
+# endif
+ }
+
+# ifndef LOG_ENABLED
+ if (!pLog)
+# endif
+ {
+ pLog = RTLogDefaultInstance();
+ if (pLog)
+ {
+ RTLogPrintf("\n!!Assertion Failed!!\n"
+ "Expression: %s\n"
+ "Location : %s(%d) %s\n",
+ pszExpr, pszFile, uLine, pszFunction);
+# ifndef IN_RC /* flushing is done automatically in RC */
+ RTLogFlush(pLog);
+# endif
+ }
+ }
+
+# ifdef IN_RING3
+ /* print to stderr, helps user and gdb debugging. */
+ fprintf(stderr,
+ "\n!!Assertion Failed!!\n"
+ "Expression: %s\n"
+ "Location : %s(%d) %s\n",
+ VALID_PTR(pszExpr) ? pszExpr : "<none>",
+ VALID_PTR(pszFile) ? pszFile : "<none>",
+ uLine,
+ VALID_PTR(pszFunction) ? pszFunction : "");
+ fflush(stderr);
+# endif
+#endif /* !IN_RING0 */
+
+ RTErrVarsRestore(&SavedErrVars);
+ }
+}
+RT_EXPORT_SYMBOL(RTAssertMsg1);
+
+
+/**
+ * Worker for RTAssertMsg2V and RTAssertMsg2AddV
+ *
+ * @param fInitial True if it's RTAssertMsg2V, otherwise false.
+ * @param pszFormat The message format string.
+ * @param va The format arguments.
+ */
+static void rtAssertMsg2Worker(bool fInitial, const char *pszFormat, va_list va)
+{
+ va_list vaCopy;
+ size_t cch;
+
+ /*
+ * The global first.
+ */
+ if (fInitial)
+ {
+ va_copy(vaCopy, va);
+ cch = RTStrPrintfV(g_szRTAssertMsg2, sizeof(g_szRTAssertMsg2), pszFormat, vaCopy);
+ ASMAtomicWriteU32(&g_cchRTAssertMsg2, (uint32_t)cch);
+ va_end(vaCopy);
+ }
+ else
+ {
+ cch = ASMAtomicReadU32(&g_cchRTAssertMsg2);
+ if (cch < sizeof(g_szRTAssertMsg2) - 4)
+ {
+ va_copy(vaCopy, va);
+ cch += RTStrPrintfV(&g_szRTAssertMsg2[cch], sizeof(g_szRTAssertMsg2) - cch, pszFormat, vaCopy);
+ ASMAtomicWriteU32(&g_cchRTAssertMsg2, (uint32_t)cch);
+ va_end(vaCopy);
+ }
+ }
+
+ /*
+ * If not quiet, make some noise.
+ */
+ if (!RTAssertAreQuiet())
+ {
+ RTERRVARS SavedErrVars;
+ RTErrVarsSave(&SavedErrVars);
+
+#ifdef IN_RING0
+# ifdef IN_GUEST_R0
+ va_copy(vaCopy, va);
+ RTLogBackdoorPrintfV(pszFormat, vaCopy);
+ va_end(vaCopy);
+# endif
+ /** @todo fully integrate this with the logger... play safe a bit for now. */
+ rtR0AssertNativeMsg2V(fInitial, pszFormat, va);
+
+#else /* !IN_RING0 */
+# if !defined(IN_RING3) && !defined(LOG_NO_COM)
+# if 0 /* Enable this iff you have a COM port and really want this debug info. */
+ va_copy(vaCopy, va);
+ RTLogComPrintfV(pszFormat, vaCopy);
+ va_end(vaCopy);
+# endif
+# endif
+
+ PRTLOGGER pLog = RTLogRelGetDefaultInstance();
+ if (pLog)
+ {
+ va_copy(vaCopy, va);
+ RTLogRelPrintfV(pszFormat, vaCopy);
+ va_end(vaCopy);
+# ifndef IN_RC /* flushing is done automatically in RC */
+ RTLogFlush(pLog);
+# endif
+ }
+
+ pLog = RTLogDefaultInstance();
+ if (pLog)
+ {
+ va_copy(vaCopy, va);
+ RTLogPrintfV(pszFormat, vaCopy);
+ va_end(vaCopy);
+# ifndef IN_RC /* flushing is done automatically in RC */
+ RTLogFlush(pLog);
+#endif
+ }
+
+# ifdef IN_RING3
+ /* print to stderr, helps user and gdb debugging. */
+ char szMsg[sizeof(g_szRTAssertMsg2)];
+ va_copy(vaCopy, va);
+ RTStrPrintfV(szMsg, sizeof(szMsg), pszFormat, vaCopy);
+ va_end(vaCopy);
+ fprintf(stderr, "%s", szMsg);
+ fflush(stderr);
+# endif
+#endif /* !IN_RING0 */
+
+ RTErrVarsRestore(&SavedErrVars);
+ }
+}
+
+
+RTDECL(void) RTAssertMsg2V(const char *pszFormat, va_list va)
+{
+ rtAssertMsg2Worker(true /*fInitial*/, pszFormat, va);
+}
+RT_EXPORT_SYMBOL(RTAssertMsg2V);
+
+
+RTDECL(void) RTAssertMsg2AddV(const char *pszFormat, va_list va)
+{
+ rtAssertMsg2Worker(false /*fInitial*/, pszFormat, va);
+}
+RT_EXPORT_SYMBOL(RTAssertMsg2AddV);
+
--- /dev/null
+/* $Id: thread.cpp $ */
+/** @file
+ * IPRT - Threads, common routines.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP RTLOGGROUP_THREAD
+#include <iprt/thread.h>
+#include "internal/iprt.h"
+
+#include <iprt/log.h>
+#include <iprt/avl.h>
+#include <iprt/alloc.h>
+#include <iprt/assert.h>
+#include <iprt/lockvalidator.h>
+#include <iprt/semaphore.h>
+#ifdef IN_RING0
+# include <iprt/spinlock.h>
+#endif
+#include <iprt/asm.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
+#include "internal/magics.h"
+#include "internal/thread.h"
+#include "internal/sched.h"
+#include "internal/process.h"
+#ifdef RT_WITH_ICONV_CACHE
+# include "internal/string.h"
+#endif
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+#ifdef IN_RING0
+# define RT_THREAD_LOCK_RW() RTSpinlockAcquire(g_ThreadSpinlock)
+# define RT_THREAD_UNLOCK_RW() RTSpinlockRelease(g_ThreadSpinlock)
+# define RT_THREAD_LOCK_RD() RTSpinlockAcquire(g_ThreadSpinlock)
+# define RT_THREAD_UNLOCK_RD() RTSpinlockRelease(g_ThreadSpinlock)
+#else
+# define RT_THREAD_LOCK_RW() rtThreadLockRW()
+# define RT_THREAD_UNLOCK_RW() rtThreadUnLockRW()
+# define RT_THREAD_LOCK_RD() rtThreadLockRD()
+# define RT_THREAD_UNLOCK_RD() rtThreadUnLockRD()
+#endif
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/** The AVL thread containing the threads. */
+static PAVLPVNODECORE g_ThreadTree;
+/** The number of threads in the tree (for ring-0 termination kludge). */
+static uint32_t volatile g_cThreadInTree;
+#ifdef IN_RING3
+/** The RW lock protecting the tree. */
+static RTSEMRW g_ThreadRWSem = NIL_RTSEMRW;
+#else
+/** The spinlocks protecting the tree. */
+static RTSPINLOCK g_ThreadSpinlock = NIL_RTSPINLOCK;
+#endif
+/** Indicates whether we've been initialized or not. */
+static bool g_frtThreadInitialized;
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+static void rtThreadDestroy(PRTTHREADINT pThread);
+#ifdef IN_RING3
+static int rtThreadAdopt(RTTHREADTYPE enmType, unsigned fFlags, uint32_t fIntFlags, const char *pszName);
+#endif
+static void rtThreadRemoveLocked(PRTTHREADINT pThread);
+static PRTTHREADINT rtThreadAlloc(RTTHREADTYPE enmType, unsigned fFlags, uint32_t fIntFlags, const char *pszName);
+
+
+/** @page pg_rt_thread IPRT Thread Internals
+ *
+ * IPRT provides interface to whatever native threading that the host provides,
+ * preferably using a CRT level interface to better integrate with other libraries.
+ *
+ * Internally IPRT keeps track of threads by means of the RTTHREADINT structure.
+ * All the RTTHREADINT structures are kept in a AVL tree which is protected by a
+ * read/write lock for efficient access. A thread is inserted into the tree in
+ * three places in the code. The main thread is 'adopted' by IPRT on rtR3Init()
+ * by rtThreadAdopt(). When creating a new thread there the child and the parent
+ * race inserting the thread, this is rtThreadMain() and RTThreadCreate.
+ *
+ * RTTHREADINT objects are using reference counting as a mean of sticking around
+ * till no-one needs them any longer. Waitable threads is created with one extra
+ * reference so they won't go away until they are waited on. This introduces a
+ * major problem if we use the host thread identifier as key in the AVL tree - the
+ * host may reuse the thread identifier before the thread was waited on. So, on
+ * most platforms we are using the RTTHREADINT pointer as key and not the
+ * thread id. RTThreadSelf() then have to be implemented using a pointer stored
+ * in thread local storage (TLS).
+ *
+ * In Ring-0 we only try keep track of kernel threads created by RTThreadCreate
+ * at the moment. There we really only need the 'join' feature, but doing things
+ * the same way allow us to name threads and similar stuff.
+ */
+
+
+/**
+ * Initializes the thread database.
+ *
+ * @returns iprt status code.
+ */
+DECLHIDDEN(int) rtThreadInit(void)
+{
+#ifdef IN_RING3
+ int rc = VINF_ALREADY_INITIALIZED;
+ if (g_ThreadRWSem == NIL_RTSEMRW)
+ {
+ /*
+ * We assume the caller is the 1st thread, which we'll call 'main'.
+ * But first, we'll create the semaphore.
+ */
+ rc = RTSemRWCreateEx(&g_ThreadRWSem, RTSEMRW_FLAGS_NO_LOCK_VAL, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, NULL);
+ if (RT_SUCCESS(rc))
+ {
+ rc = rtThreadNativeInit();
+ if (RT_SUCCESS(rc))
+ rc = rtThreadAdopt(RTTHREADTYPE_DEFAULT, 0, RTTHREADINT_FLAGS_MAIN, "main");
+ if (RT_SUCCESS(rc))
+ rc = rtSchedNativeCalcDefaultPriority(RTTHREADTYPE_DEFAULT);
+ if (RT_SUCCESS(rc))
+ {
+ g_frtThreadInitialized = true;
+ return VINF_SUCCESS;
+ }
+
+ /* failed, clear out */
+ RTSemRWDestroy(g_ThreadRWSem);
+ g_ThreadRWSem = NIL_RTSEMRW;
+ }
+ }
+
+#elif defined(IN_RING0)
+ int rc;
+ /*
+ * Create the spinlock and to native init.
+ */
+ Assert(g_ThreadSpinlock == NIL_RTSPINLOCK);
+ rc = RTSpinlockCreate(&g_ThreadSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "RTThread");
+ if (RT_SUCCESS(rc))
+ {
+ rc = rtThreadNativeInit();
+ if (RT_SUCCESS(rc))
+ {
+ g_frtThreadInitialized = true;
+ return VINF_SUCCESS;
+ }
+
+ /* failed, clear out */
+ RTSpinlockDestroy(g_ThreadSpinlock);
+ g_ThreadSpinlock = NIL_RTSPINLOCK;
+ }
+#else
+# error "!IN_RING0 && !IN_RING3"
+#endif
+ return rc;
+}
+
+
+#ifdef IN_RING3
+/**
+ * Called when IPRT was first initialized in unobtrusive mode and later changed
+ * to obtrustive.
+ *
+ * This is only applicable in ring-3.
+ */
+DECLHIDDEN(void) rtThreadReInitObtrusive(void)
+{
+ rtThreadNativeReInitObtrusive();
+}
+#endif
+
+
+/**
+ * Terminates the thread database.
+ */
+DECLHIDDEN(void) rtThreadTerm(void)
+{
+#ifdef IN_RING3
+ /* we don't cleanup here yet */
+
+#elif defined(IN_RING0)
+ /* just destroy the spinlock and assume the thread is fine... */
+ RTSpinlockDestroy(g_ThreadSpinlock);
+ g_ThreadSpinlock = NIL_RTSPINLOCK;
+ if (g_ThreadTree != NULL)
+ RTAssertMsg2Weak("WARNING: g_ThreadTree=%p\n", g_ThreadTree);
+#endif
+}
+
+
+#ifdef IN_RING3
+
+DECLINLINE(void) rtThreadLockRW(void)
+{
+ if (g_ThreadRWSem == NIL_RTSEMRW)
+ rtThreadInit();
+ int rc = RTSemRWRequestWrite(g_ThreadRWSem, RT_INDEFINITE_WAIT);
+ AssertReleaseRC(rc);
+}
+
+
+DECLINLINE(void) rtThreadLockRD(void)
+{
+ if (g_ThreadRWSem == NIL_RTSEMRW)
+ rtThreadInit();
+ int rc = RTSemRWRequestRead(g_ThreadRWSem, RT_INDEFINITE_WAIT);
+ AssertReleaseRC(rc);
+}
+
+
+DECLINLINE(void) rtThreadUnLockRW(void)
+{
+ int rc = RTSemRWReleaseWrite(g_ThreadRWSem);
+ AssertReleaseRC(rc);
+}
+
+
+DECLINLINE(void) rtThreadUnLockRD(void)
+{
+ int rc = RTSemRWReleaseRead(g_ThreadRWSem);
+ AssertReleaseRC(rc);
+}
+
+
+/**
+ * Adopts the calling thread.
+ * No locks are taken or released by this function.
+ */
+static int rtThreadAdopt(RTTHREADTYPE enmType, unsigned fFlags, uint32_t fIntFlags, const char *pszName)
+{
+ int rc;
+ PRTTHREADINT pThread;
+ Assert(!(fFlags & RTTHREADFLAGS_WAITABLE));
+ fFlags &= ~RTTHREADFLAGS_WAITABLE;
+
+ /*
+ * Allocate and insert the thread.
+ * (It is vital that rtThreadNativeAdopt updates the TLS before
+ * we try inserting the thread because of locking.)
+ */
+ rc = VERR_NO_MEMORY;
+ pThread = rtThreadAlloc(enmType, fFlags, RTTHREADINT_FLAGS_ALIEN | fIntFlags, pszName);
+ if (pThread)
+ {
+ RTNATIVETHREAD NativeThread = RTThreadNativeSelf();
+ rc = rtThreadNativeAdopt(pThread);
+ if (RT_SUCCESS(rc))
+ {
+ rtThreadInsert(pThread, NativeThread);
+ rtThreadSetState(pThread, RTTHREADSTATE_RUNNING);
+ rtThreadRelease(pThread);
+ }
+ }
+ return rc;
+}
+
+/**
+ * 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)
+{
+ int rc;
+ RTTHREAD Thread;
+
+ AssertReturn(!(fFlags & RTTHREADFLAGS_WAITABLE), VERR_INVALID_PARAMETER);
+ AssertReturn(!pszName || VALID_PTR(pszName), VERR_INVALID_POINTER);
+ AssertReturn(!pThread || VALID_PTR(pThread), VERR_INVALID_POINTER);
+
+ rc = VINF_SUCCESS;
+ Thread = RTThreadSelf();
+ if (Thread == NIL_RTTHREAD)
+ {
+ /* generate a name if none was given. */
+ char szName[RTTHREAD_NAME_LEN];
+ if (!pszName || !*pszName)
+ {
+ static uint32_t s_i32AlienId = 0;
+ uint32_t i32Id = ASMAtomicIncU32(&s_i32AlienId);
+ RTStrPrintf(szName, sizeof(szName), "ALIEN-%RX32", i32Id);
+ pszName = szName;
+ }
+
+ /* try adopt it */
+ rc = rtThreadAdopt(enmType, fFlags, 0, pszName);
+ Thread = RTThreadSelf();
+ Log(("RTThreadAdopt: %RTthrd %RTnthrd '%s' enmType=%d fFlags=%#x rc=%Rrc\n",
+ Thread, RTThreadNativeSelf(), pszName, enmType, fFlags, rc));
+ }
+ else
+ Log(("RTThreadAdopt: %RTthrd %RTnthrd '%s' enmType=%d fFlags=%#x - already adopted!\n",
+ Thread, RTThreadNativeSelf(), pszName, enmType, fFlags));
+
+ if (pThread)
+ *pThread = Thread;
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTThreadAdopt);
+
+
+/**
+ * Get the thread handle of the current thread, automatically adopting alien
+ * threads.
+ *
+ * @returns Thread handle.
+ */
+RTDECL(RTTHREAD) RTThreadSelfAutoAdopt(void)
+{
+ RTTHREAD hSelf = RTThreadSelf();
+ if (RT_UNLIKELY(hSelf == NIL_RTTHREAD))
+ RTThreadAdopt(RTTHREADTYPE_DEFAULT, 0, NULL, &hSelf);
+ return hSelf;
+}
+RT_EXPORT_SYMBOL(RTThreadSelfAutoAdopt);
+
+#endif /* IN_RING3 */
+
+/**
+ * Allocates a per thread data structure and initializes the basic fields.
+ *
+ * @returns Pointer to per thread data structure.
+ * This is reference once.
+ * @returns NULL on failure.
+ * @param enmType The thread type.
+ * @param fFlags The thread flags.
+ * @param fIntFlags The internal thread flags.
+ * @param pszName Pointer to the thread name.
+ */
+PRTTHREADINT rtThreadAlloc(RTTHREADTYPE enmType, unsigned fFlags, uint32_t fIntFlags, const char *pszName)
+{
+ PRTTHREADINT pThread = (PRTTHREADINT)RTMemAllocZ(sizeof(RTTHREADINT));
+ if (pThread)
+ {
+ size_t cchName;
+ int rc;
+
+ pThread->Core.Key = (void*)NIL_RTTHREAD;
+ pThread->u32Magic = RTTHREADINT_MAGIC;
+ cchName = strlen(pszName);
+ if (cchName >= RTTHREAD_NAME_LEN)
+ cchName = RTTHREAD_NAME_LEN - 1;
+ memcpy(pThread->szName, pszName, cchName);
+ pThread->szName[cchName] = '\0';
+ pThread->cRefs = 2 + !!(fFlags & RTTHREADFLAGS_WAITABLE); /* And extra reference if waitable. */
+ pThread->rc = VERR_PROCESS_RUNNING; /** @todo get a better error code! */
+ pThread->enmType = enmType;
+ pThread->fFlags = fFlags;
+ pThread->fIntFlags = fIntFlags;
+ pThread->enmState = RTTHREADSTATE_INITIALIZING;
+ pThread->fReallySleeping = false;
+#ifdef IN_RING3
+ rtLockValidatorInitPerThread(&pThread->LockValidator);
+#endif
+#ifdef RT_WITH_ICONV_CACHE
+ rtStrIconvCacheInit(pThread);
+#endif
+ rc = RTSemEventMultiCreate(&pThread->EventUser);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTSemEventMultiCreate(&pThread->EventTerminated);
+ if (RT_SUCCESS(rc))
+ return pThread;
+ RTSemEventMultiDestroy(pThread->EventUser);
+ }
+ RTMemFree(pThread);
+ }
+ return NULL;
+}
+
+
+/**
+ * Insert the per thread data structure into the tree.
+ *
+ * This can be called from both the thread it self and the parent,
+ * thus it must handle insertion failures in a nice manner.
+ *
+ * @param pThread Pointer to thread structure allocated by rtThreadAlloc().
+ * @param NativeThread The native thread id.
+ */
+DECLHIDDEN(void) rtThreadInsert(PRTTHREADINT pThread, RTNATIVETHREAD NativeThread)
+{
+ Assert(pThread);
+ Assert(pThread->u32Magic == RTTHREADINT_MAGIC);
+
+ {
+ RT_THREAD_LOCK_RW();
+
+ /*
+ * Do not insert a terminated thread.
+ *
+ * This may happen if the thread finishes before the RTThreadCreate call
+ * gets this far. Since the OS may quickly reuse the native thread ID
+ * it should not be reinserted at this point.
+ */
+ if (rtThreadGetState(pThread) != RTTHREADSTATE_TERMINATED)
+ {
+ /*
+ * Before inserting we must check if there is a thread with this id
+ * in the tree already. We're racing parent and child on insert here
+ * so that the handle is valid in both ends when they return / start.
+ *
+ * If it's not ourself we find, it's a dead alien thread and we will
+ * unlink it from the tree. Alien threads will be released at this point.
+ */
+ PRTTHREADINT pThreadOther = (PRTTHREADINT)RTAvlPVGet(&g_ThreadTree, (void *)NativeThread);
+ if (pThreadOther != pThread)
+ {
+ bool fRc;
+ /* remove dead alien if any */
+ if (pThreadOther)
+ {
+ AssertMsg(pThreadOther->fIntFlags & RTTHREADINT_FLAGS_ALIEN, ("%p:%s; %p:%s\n", pThread, pThread->szName, pThreadOther, pThreadOther->szName));
+ ASMAtomicBitClear(&pThread->fIntFlags, RTTHREADINT_FLAG_IN_TREE_BIT);
+ rtThreadRemoveLocked(pThreadOther);
+ if (pThreadOther->fIntFlags & RTTHREADINT_FLAGS_ALIEN)
+ rtThreadRelease(pThreadOther);
+ }
+
+ /* insert the thread */
+ ASMAtomicWritePtr(&pThread->Core.Key, (void *)NativeThread);
+ fRc = RTAvlPVInsert(&g_ThreadTree, &pThread->Core);
+ ASMAtomicOrU32(&pThread->fIntFlags, RTTHREADINT_FLAG_IN_TREE);
+ if (fRc)
+ ASMAtomicIncU32(&g_cThreadInTree);
+
+ AssertReleaseMsg(fRc, ("Lock problem? %p (%RTnthrd) %s\n", pThread, NativeThread, pThread->szName));
+ NOREF(fRc);
+ }
+ }
+
+ RT_THREAD_UNLOCK_RW();
+ }
+}
+
+
+/**
+ * Removes the thread from the AVL tree, call owns the tree lock
+ * and has cleared the RTTHREADINT_FLAG_IN_TREE bit.
+ *
+ * @param pThread The thread to remove.
+ */
+static void rtThreadRemoveLocked(PRTTHREADINT pThread)
+{
+ PRTTHREADINT pThread2 = (PRTTHREADINT)RTAvlPVRemove(&g_ThreadTree, pThread->Core.Key);
+#if !defined(RT_OS_OS2) /** @todo this asserts for threads created by NSPR */
+ AssertMsg(pThread2 == pThread, ("%p(%s) != %p (%p/%s)\n", pThread2, pThread2 ? pThread2->szName : "<null>",
+ pThread, pThread->Core.Key, pThread->szName));
+#endif
+ if (pThread2)
+ ASMAtomicDecU32(&g_cThreadInTree);
+}
+
+
+/**
+ * Removes the thread from the AVL tree.
+ *
+ * @param pThread The thread to remove.
+ */
+static void rtThreadRemove(PRTTHREADINT pThread)
+{
+ RT_THREAD_LOCK_RW();
+ if (ASMAtomicBitTestAndClear(&pThread->fIntFlags, RTTHREADINT_FLAG_IN_TREE_BIT))
+ rtThreadRemoveLocked(pThread);
+ RT_THREAD_UNLOCK_RW();
+}
+
+
+/**
+ * Checks if a thread is alive or not.
+ *
+ * @returns true if the thread is alive (or we don't really know).
+ * @returns false if the thread has surely terminate.
+ */
+DECLINLINE(bool) rtThreadIsAlive(PRTTHREADINT pThread)
+{
+ return !(pThread->fIntFlags & RTTHREADINT_FLAGS_TERMINATED);
+}
+
+
+/**
+ * Gets a thread by it's native ID.
+ *
+ * @returns pointer to the thread structure.
+ * @returns NULL if not a thread IPRT knows.
+ * @param NativeThread The native thread id.
+ */
+DECLHIDDEN(PRTTHREADINT) rtThreadGetByNative(RTNATIVETHREAD NativeThread)
+{
+ PRTTHREADINT pThread;
+ /*
+ * Simple tree lookup.
+ */
+ RT_THREAD_LOCK_RD();
+ pThread = (PRTTHREADINT)RTAvlPVGet(&g_ThreadTree, (void *)NativeThread);
+ RT_THREAD_UNLOCK_RD();
+ return pThread;
+}
+
+
+/**
+ * Gets the per thread data structure for a thread handle.
+ *
+ * @returns Pointer to the per thread data structure for Thread.
+ * The caller must release the thread using rtThreadRelease().
+ * @returns NULL if Thread was not found.
+ * @param Thread Thread id which structure is to be returned.
+ */
+DECLHIDDEN(PRTTHREADINT) rtThreadGet(RTTHREAD Thread)
+{
+ if ( Thread != NIL_RTTHREAD
+ && VALID_PTR(Thread))
+ {
+ PRTTHREADINT pThread = (PRTTHREADINT)Thread;
+ if ( pThread->u32Magic == RTTHREADINT_MAGIC
+ && pThread->cRefs > 0)
+ {
+ ASMAtomicIncU32(&pThread->cRefs);
+ return pThread;
+ }
+ }
+
+ AssertMsgFailed(("Thread=%RTthrd\n", Thread));
+ return NULL;
+}
+
+/**
+ * Release a per thread data structure.
+ *
+ * @returns New reference count.
+ * @param pThread The thread structure to release.
+ */
+DECLHIDDEN(uint32_t) rtThreadRelease(PRTTHREADINT pThread)
+{
+ uint32_t cRefs;
+
+ Assert(pThread);
+ if (pThread->cRefs >= 1)
+ {
+ cRefs = ASMAtomicDecU32(&pThread->cRefs);
+ if (!cRefs)
+ rtThreadDestroy(pThread);
+ }
+ else
+ {
+ cRefs = 0;
+ AssertFailed();
+ }
+ return cRefs;
+}
+
+
+/**
+ * Destroys the per thread data.
+ *
+ * @param pThread The thread to destroy.
+ */
+static void rtThreadDestroy(PRTTHREADINT pThread)
+{
+ RTSEMEVENTMULTI hEvt1, hEvt2;
+ /*
+ * Remove it from the tree and mark it as dead.
+ *
+ * Threads that has seen rtThreadTerminate and should already have been
+ * removed from the tree. There is probably no thread that should
+ * require removing here. However, be careful making sure that cRefs
+ * isn't 0 if we do or we'll blow up because the strict locking code
+ * will be calling us back.
+ */
+ if (ASMBitTest(&pThread->fIntFlags, RTTHREADINT_FLAG_IN_TREE_BIT))
+ {
+ ASMAtomicIncU32(&pThread->cRefs);
+ rtThreadRemove(pThread);
+ ASMAtomicDecU32(&pThread->cRefs);
+ }
+
+ /*
+ * Invalidate the thread structure.
+ */
+#ifdef IN_RING3
+ rtLockValidatorSerializeDestructEnter();
+
+ rtLockValidatorDeletePerThread(&pThread->LockValidator);
+#endif
+#ifdef RT_WITH_ICONV_CACHE
+ rtStrIconvCacheDestroy(pThread);
+#endif
+ ASMAtomicXchgU32(&pThread->u32Magic, RTTHREADINT_MAGIC_DEAD);
+ ASMAtomicWritePtr(&pThread->Core.Key, (void *)NIL_RTTHREAD);
+ pThread->enmType = RTTHREADTYPE_INVALID;
+ hEvt1 = pThread->EventUser;
+ pThread->EventUser = NIL_RTSEMEVENTMULTI;
+ hEvt2 = pThread->EventTerminated;
+ pThread->EventTerminated = NIL_RTSEMEVENTMULTI;
+
+#ifdef IN_RING3
+ rtLockValidatorSerializeDestructLeave();
+#endif
+
+ /*
+ * Destroy semaphore resources and free the bugger.
+ */
+ RTSemEventMultiDestroy(hEvt1);
+ if (hEvt2 != NIL_RTSEMEVENTMULTI)
+ RTSemEventMultiDestroy(hEvt2);
+
+ rtThreadNativeDestroy(pThread);
+ RTMemFree(pThread);
+}
+
+
+/**
+ * Terminates the thread.
+ * Called by the thread wrapper function when the thread terminates.
+ *
+ * @param pThread The thread structure.
+ * @param rc The thread result code.
+ */
+DECLHIDDEN(void) rtThreadTerminate(PRTTHREADINT pThread, int rc)
+{
+ Assert(pThread->cRefs >= 1);
+
+#ifdef IPRT_WITH_GENERIC_TLS
+ /*
+ * Destroy TLS entries.
+ */
+ rtThreadTlsDestruction(pThread);
+#endif /* IPRT_WITH_GENERIC_TLS */
+
+ /*
+ * Set the rc, mark it terminated and signal anyone waiting.
+ */
+ pThread->rc = rc;
+ rtThreadSetState(pThread, RTTHREADSTATE_TERMINATED);
+ ASMAtomicOrU32(&pThread->fIntFlags, RTTHREADINT_FLAGS_TERMINATED);
+ if (pThread->EventTerminated != NIL_RTSEMEVENTMULTI)
+ RTSemEventMultiSignal(pThread->EventTerminated);
+
+ /*
+ * Remove the thread from the tree so that there will be no
+ * key clashes in the AVL tree and release our reference to ourself.
+ */
+ rtThreadRemove(pThread);
+ rtThreadRelease(pThread);
+}
+
+
+/**
+ * The common thread main function.
+ * This is called by rtThreadNativeMain().
+ *
+ * @returns The status code of the thread.
+ * pThread is dereference by the thread before returning!
+ * @param pThread The thread structure.
+ * @param NativeThread The native thread id.
+ * @param pszThreadName The name of the thread (purely a dummy for backtrace).
+ */
+DECLCALLBACK(DECLHIDDEN(int)) rtThreadMain(PRTTHREADINT pThread, RTNATIVETHREAD NativeThread, const char *pszThreadName)
+{
+ int rc;
+ NOREF(pszThreadName);
+ rtThreadInsert(pThread, NativeThread);
+ Log(("rtThreadMain: Starting: pThread=%p NativeThread=%RTnthrd Name=%s pfnThread=%p pvUser=%p\n",
+ pThread, NativeThread, pThread->szName, pThread->pfnThread, pThread->pvUser));
+
+ /*
+ * Change the priority.
+ */
+ rc = rtThreadNativeSetPriority(pThread, pThread->enmType);
+#ifdef IN_RING3
+ AssertMsgRC(rc, ("Failed to set priority of thread %p (%RTnthrd / %s) to enmType=%d enmPriority=%d rc=%Rrc\n",
+ pThread, NativeThread, pThread->szName, pThread->enmType, g_enmProcessPriority, rc));
+#else
+ AssertMsgRC(rc, ("Failed to set priority of thread %p (%RTnthrd / %s) to enmType=%d rc=%Rrc\n",
+ pThread, NativeThread, pThread->szName, pThread->enmType, rc));
+#endif
+
+ /*
+ * Call thread function and terminate when it returns.
+ */
+ rtThreadSetState(pThread, RTTHREADSTATE_RUNNING);
+ rc = pThread->pfnThread(pThread, pThread->pvUser);
+
+ /*
+ * Paranoia checks for leftover resources.
+ */
+#ifdef RTSEMRW_STRICT
+ int32_t cWrite = ASMAtomicReadS32(&pThread->cWriteLocks);
+ Assert(!cWrite);
+ int32_t cRead = ASMAtomicReadS32(&pThread->cReadLocks);
+ Assert(!cRead);
+#endif
+
+ Log(("rtThreadMain: Terminating: rc=%d pThread=%p NativeThread=%RTnthrd Name=%s pfnThread=%p pvUser=%p\n",
+ rc, pThread, NativeThread, pThread->szName, pThread->pfnThread, pThread->pvUser));
+ rtThreadTerminate(pThread, rc);
+ return rc;
+}
+
+
+/**
+ * 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.
+ */
+RTDECL(int) RTThreadCreate(PRTTHREAD pThread, PFNRTTHREAD pfnThread, void *pvUser, size_t cbStack,
+ RTTHREADTYPE enmType, unsigned fFlags, const char *pszName)
+{
+ int rc;
+ PRTTHREADINT pThreadInt;
+
+ LogFlow(("RTThreadCreate: pThread=%p pfnThread=%p pvUser=%p cbStack=%#x enmType=%d fFlags=%#x pszName=%p:{%s}\n",
+ pThread, pfnThread, pvUser, cbStack, enmType, fFlags, pszName, pszName));
+
+ /*
+ * Validate input.
+ */
+ if (!VALID_PTR(pThread) && pThread)
+ {
+ Assert(VALID_PTR(pThread));
+ return VERR_INVALID_PARAMETER;
+ }
+ if (!VALID_PTR(pfnThread))
+ {
+ Assert(VALID_PTR(pfnThread));
+ return VERR_INVALID_PARAMETER;
+ }
+ if (!pszName || !*pszName || strlen(pszName) >= RTTHREAD_NAME_LEN)
+ {
+ AssertMsgFailed(("pszName=%s (max len is %d because of logging)\n", pszName, RTTHREAD_NAME_LEN - 1));
+ return VERR_INVALID_PARAMETER;
+ }
+ if (fFlags & ~RTTHREADFLAGS_MASK)
+ {
+ AssertMsgFailed(("fFlags=%#x\n", fFlags));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ /*
+ * Allocate thread argument.
+ */
+ pThreadInt = rtThreadAlloc(enmType, fFlags, 0, pszName);
+ if (pThreadInt)
+ {
+ RTNATIVETHREAD NativeThread;
+
+ pThreadInt->pfnThread = pfnThread;
+ pThreadInt->pvUser = pvUser;
+ pThreadInt->cbStack = cbStack;
+
+ rc = rtThreadNativeCreate(pThreadInt, &NativeThread);
+ if (RT_SUCCESS(rc))
+ {
+ rtThreadInsert(pThreadInt, NativeThread);
+ rtThreadRelease(pThreadInt);
+ Log(("RTThreadCreate: Created thread %p (%p) %s\n", pThreadInt, NativeThread, pszName));
+ if (pThread)
+ *pThread = pThreadInt;
+ return VINF_SUCCESS;
+ }
+
+ pThreadInt->cRefs = 1;
+ rtThreadRelease(pThreadInt);
+ }
+ else
+ rc = VERR_NO_TMP_MEMORY;
+ LogFlow(("RTThreadCreate: Failed to create thread, rc=%Rrc\n", rc));
+ AssertReleaseRC(rc);
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTThreadCreate);
+
+
+/**
+ * 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)
+{
+ char szName[RTTHREAD_NAME_LEN * 2];
+ RTStrPrintfV(szName, sizeof(szName), pszNameFmt, va);
+ return RTThreadCreate(pThread, pfnThread, pvUser, cbStack, enmType, fFlags, szName);
+}
+RT_EXPORT_SYMBOL(RTThreadCreateV);
+
+
+/**
+ * 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, ...)
+{
+ va_list va;
+ int rc;
+ va_start(va, pszNameFmt);
+ rc = RTThreadCreateV(pThread, pfnThread, pvUser, cbStack, enmType, fFlags, pszNameFmt, va);
+ va_end(va);
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTThreadCreateF);
+
+
+/**
+ * Gets the native thread id of a IPRT thread.
+ *
+ * @returns The native thread id.
+ * @param Thread The IPRT thread.
+ */
+RTDECL(RTNATIVETHREAD) RTThreadGetNative(RTTHREAD Thread)
+{
+ PRTTHREADINT pThread = rtThreadGet(Thread);
+ if (pThread)
+ {
+ RTNATIVETHREAD NativeThread = (RTNATIVETHREAD)pThread->Core.Key;
+ rtThreadRelease(pThread);
+ return NativeThread;
+ }
+ return NIL_RTNATIVETHREAD;
+}
+RT_EXPORT_SYMBOL(RTThreadGetNative);
+
+
+/**
+ * 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)
+{
+ PRTTHREADINT pThread = rtThreadGetByNative(NativeThread);
+ if (pThread)
+ return pThread;
+ return NIL_RTTHREAD;
+}
+RT_EXPORT_SYMBOL(RTThreadFromNative);
+
+
+/**
+ * Gets the name of the current thread thread.
+ *
+ * @returns Pointer to readonly name string.
+ * @returns NULL on failure.
+ */
+RTDECL(const char *) RTThreadSelfName(void)
+{
+ RTTHREAD Thread = RTThreadSelf();
+ if (Thread != NIL_RTTHREAD)
+ {
+ PRTTHREADINT pThread = rtThreadGet(Thread);
+ if (pThread)
+ {
+ const char *szName = pThread->szName;
+ rtThreadRelease(pThread);
+ return szName;
+ }
+ }
+ return NULL;
+}
+RT_EXPORT_SYMBOL(RTThreadSelfName);
+
+
+/**
+ * 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)
+{
+ PRTTHREADINT pThread;
+ if (Thread == NIL_RTTHREAD)
+ return NULL;
+ pThread = rtThreadGet(Thread);
+ if (pThread)
+ {
+ const char *szName = pThread->szName;
+ rtThreadRelease(pThread);
+ return szName;
+ }
+ return NULL;
+}
+RT_EXPORT_SYMBOL(RTThreadGetName);
+
+
+/**
+ * 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)
+{
+ /*
+ * Validate input.
+ */
+ PRTTHREADINT pThread;
+ size_t cchName = strlen(pszName);
+ if (cchName >= RTTHREAD_NAME_LEN)
+ {
+ AssertMsgFailed(("pszName=%s is too long, max is %d\n", pszName, RTTHREAD_NAME_LEN - 1));
+ return VERR_INVALID_PARAMETER;
+ }
+ pThread = rtThreadGet(Thread);
+ if (!pThread)
+ return VERR_INVALID_HANDLE;
+
+ /*
+ * Update the name.
+ */
+ pThread->szName[cchName] = '\0'; /* paranoia */
+ memcpy(pThread->szName, pszName, cchName);
+ rtThreadRelease(pThread);
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTThreadSetName);
+
+
+/**
+ * Checks if the specified thread is the main thread.
+ *
+ * @returns true if it is, false if it isn't.
+ *
+ * @param hThread The thread handle.
+ *
+ * @remarks This function may not return the correct value when rtR3Init was
+ * called on a thread of the than the main one. This could for
+ * instance happen when the DLL/DYLIB/SO containing IPRT is dynamically
+ * loaded at run time by a different thread.
+ */
+RTDECL(bool) RTThreadIsMain(RTTHREAD hThread)
+{
+ PRTTHREADINT pThread = rtThreadGet(hThread);
+ if (pThread)
+ {
+ bool fRc = !!(pThread->fIntFlags & RTTHREADINT_FLAGS_MAIN);
+ rtThreadRelease(pThread);
+ return fRc;
+ }
+ return false;
+}
+RT_EXPORT_SYMBOL(RTThreadIsMain);
+
+
+RTDECL(bool) RTThreadIsSelfAlive(void)
+{
+ if (g_frtThreadInitialized)
+ {
+ RTTHREAD hSelf = RTThreadSelf();
+ if (hSelf != NIL_RTTHREAD)
+ {
+ /*
+ * Inspect the thread state. ASSUMES thread state order.
+ */
+ RTTHREADSTATE enmState = rtThreadGetState(hSelf);
+ if ( enmState >= RTTHREADSTATE_RUNNING
+ && enmState <= RTTHREADSTATE_END)
+ return true;
+ }
+ }
+ return false;
+}
+RT_EXPORT_SYMBOL(RTThreadIsSelfAlive);
+
+
+RTDECL(bool) RTThreadIsSelfKnown(void)
+{
+ if (g_frtThreadInitialized)
+ {
+ RTTHREAD hSelf = RTThreadSelf();
+ if (hSelf != NIL_RTTHREAD)
+ return true;
+ }
+ return false;
+}
+RT_EXPORT_SYMBOL(RTThreadIsSelfKnown);
+
+
+RTDECL(bool) RTThreadIsInitialized(void)
+{
+ return g_frtThreadInitialized;
+}
+RT_EXPORT_SYMBOL(RTThreadIsInitialized);
+
+
+/**
+ * Signal the user event.
+ *
+ * @returns iprt status code.
+ */
+RTDECL(int) RTThreadUserSignal(RTTHREAD Thread)
+{
+ int rc;
+ PRTTHREADINT pThread = rtThreadGet(Thread);
+ if (pThread)
+ {
+ rc = RTSemEventMultiSignal(pThread->EventUser);
+ rtThreadRelease(pThread);
+ }
+ else
+ rc = VERR_INVALID_HANDLE;
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTThreadUserSignal);
+
+
+/**
+ * Wait for the user event, resume 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) RTThreadUserWait(RTTHREAD Thread, RTMSINTERVAL cMillies)
+{
+ int rc;
+ PRTTHREADINT pThread = rtThreadGet(Thread);
+ if (pThread)
+ {
+ rc = RTSemEventMultiWait(pThread->EventUser, cMillies);
+ rtThreadRelease(pThread);
+ }
+ else
+ rc = VERR_INVALID_HANDLE;
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTThreadUserWait);
+
+
+/**
+ * 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)
+{
+ int rc;
+ PRTTHREADINT pThread = rtThreadGet(Thread);
+ if (pThread)
+ {
+ rc = RTSemEventMultiWaitNoResume(pThread->EventUser, cMillies);
+ rtThreadRelease(pThread);
+ }
+ else
+ rc = VERR_INVALID_HANDLE;
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTThreadUserWaitNoResume);
+
+
+/**
+ * Reset the user event.
+ *
+ * @returns iprt status code.
+ * @param Thread The thread to reset.
+ */
+RTDECL(int) RTThreadUserReset(RTTHREAD Thread)
+{
+ int rc;
+ PRTTHREADINT pThread = rtThreadGet(Thread);
+ if (pThread)
+ {
+ rc = RTSemEventMultiReset(pThread->EventUser);
+ rtThreadRelease(pThread);
+ }
+ else
+ rc = VERR_INVALID_HANDLE;
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTThreadUserReset);
+
+
+/**
+ * Wait for the thread to terminate.
+ *
+ * @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.
+ * @param fAutoResume Whether or not to resume the wait on VERR_INTERRUPTED.
+ */
+static int rtThreadWait(RTTHREAD Thread, RTMSINTERVAL cMillies, int *prc, bool fAutoResume)
+{
+ int rc = VERR_INVALID_HANDLE;
+ if (Thread != NIL_RTTHREAD)
+ {
+ PRTTHREADINT pThread = rtThreadGet(Thread);
+ if (pThread)
+ {
+ if (pThread->fFlags & RTTHREADFLAGS_WAITABLE)
+ {
+ if (fAutoResume)
+ rc = RTSemEventMultiWait(pThread->EventTerminated, cMillies);
+ else
+ rc = RTSemEventMultiWaitNoResume(pThread->EventTerminated, cMillies);
+ if (RT_SUCCESS(rc))
+ {
+ if (prc)
+ *prc = pThread->rc;
+
+ /*
+ * If the thread is marked as waitable, we'll do one additional
+ * release in order to free up the thread structure (see how we
+ * init cRef in rtThreadAlloc()).
+ */
+ if (ASMAtomicBitTestAndClear(&pThread->fFlags, RTTHREADFLAGS_WAITABLE_BIT))
+ {
+ rtThreadRelease(pThread);
+#ifdef IN_RING0
+ /*
+ * IPRT termination kludge. Call native code to make sure
+ * the last thread is really out of IPRT to prevent it from
+ * crashing after we destroyed the spinlock in rtThreadTerm.
+ */
+ if ( ASMAtomicReadU32(&g_cThreadInTree) == 1
+ && ASMAtomicReadU32(&pThread->cRefs) > 1)
+ rtThreadNativeWaitKludge(pThread);
+#endif
+ }
+ }
+ }
+ else
+ {
+ rc = VERR_THREAD_NOT_WAITABLE;
+ AssertRC(rc);
+ }
+ rtThreadRelease(pThread);
+ }
+ }
+ return rc;
+}
+
+
+/**
+ * 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)
+{
+ int rc = rtThreadWait(Thread, cMillies, prc, true);
+ Assert(rc != VERR_INTERRUPTED);
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTThreadWait);
+
+
+/**
+ * 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)
+{
+ return rtThreadWait(Thread, cMillies, prc, false);
+}
+RT_EXPORT_SYMBOL(RTThreadWaitNoResume);
+
+
+/**
+ * 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.
+ */
+RTDECL(int) RTThreadSetType(RTTHREAD Thread, RTTHREADTYPE enmType)
+{
+ /*
+ * Validate input.
+ */
+ int rc;
+ if ( enmType > RTTHREADTYPE_INVALID
+ && enmType < RTTHREADTYPE_END)
+ {
+ PRTTHREADINT pThread = rtThreadGet(Thread);
+ if (pThread)
+ {
+ if (rtThreadIsAlive(pThread))
+ {
+ /*
+ * Do the job.
+ */
+ RT_THREAD_LOCK_RW();
+ rc = rtThreadNativeSetPriority(pThread, enmType);
+ if (RT_SUCCESS(rc))
+ ASMAtomicXchgSize(&pThread->enmType, enmType);
+ RT_THREAD_UNLOCK_RW();
+ if (RT_FAILURE(rc))
+ Log(("RTThreadSetType: failed on thread %p (%s), rc=%Rrc!!!\n", Thread, pThread->szName, rc));
+ }
+ else
+ rc = VERR_THREAD_IS_DEAD;
+ rtThreadRelease(pThread);
+ }
+ else
+ rc = VERR_INVALID_HANDLE;
+ }
+ else
+ {
+ AssertMsgFailed(("enmType=%d\n", enmType));
+ rc = VERR_INVALID_PARAMETER;
+ }
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTThreadSetType);
+
+
+/**
+ * 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)
+{
+ RTTHREADTYPE enmType = RTTHREADTYPE_INVALID;
+ PRTTHREADINT pThread = rtThreadGet(Thread);
+ if (pThread)
+ {
+ enmType = pThread->enmType;
+ rtThreadRelease(pThread);
+ }
+ return enmType;
+}
+RT_EXPORT_SYMBOL(RTThreadGetType);
+
+#ifdef IN_RING3
+
+/**
+ * Recalculates scheduling attributes for the default process
+ * priority using the specified priority type for the calling thread.
+ *
+ * The scheduling attributes are targeted at threads and they are protected
+ * by the thread read-write semaphore, that's why RTProc is forwarding the
+ * operation to RTThread.
+ *
+ * @returns iprt status code.
+ * @remarks Will only work for strict builds.
+ */
+int rtThreadDoCalcDefaultPriority(RTTHREADTYPE enmType)
+{
+ RT_THREAD_LOCK_RW();
+ int rc = rtSchedNativeCalcDefaultPriority(enmType);
+ RT_THREAD_UNLOCK_RW();
+ return rc;
+}
+
+
+/**
+ * Thread enumerator - sets the priority of one thread.
+ *
+ * @returns 0 to continue.
+ * @returns !0 to stop. In our case a VERR_ code.
+ * @param pNode The thread node.
+ * @param pvUser The new priority.
+ */
+static DECLCALLBACK(int) rtThreadSetPriorityOne(PAVLPVNODECORE pNode, void *pvUser)
+{
+ PRTTHREADINT pThread = (PRTTHREADINT)pNode;
+ if (!rtThreadIsAlive(pThread))
+ return VINF_SUCCESS;
+ int rc = rtThreadNativeSetPriority(pThread, pThread->enmType);
+ if (RT_SUCCESS(rc)) /* hide any warnings */
+ return VINF_SUCCESS;
+ NOREF(pvUser);
+ return rc;
+}
+
+
+/**
+ * Attempts to alter the priority of the current process.
+ *
+ * The scheduling attributes are targeted at threads and they are protected
+ * by the thread read-write semaphore, that's why RTProc is forwarding the
+ * operation to RTThread. This operation also involves updating all thread
+ * which is much faster done from RTThread.
+ *
+ * @returns iprt status code.
+ * @param enmPriority The new priority.
+ */
+DECLHIDDEN(int) rtThreadDoSetProcPriority(RTPROCPRIORITY enmPriority)
+{
+ LogFlow(("rtThreadDoSetProcPriority: enmPriority=%d\n", enmPriority));
+
+ /*
+ * First validate that we're allowed by the OS to use all the
+ * scheduling attributes defined by the specified process priority.
+ */
+ RT_THREAD_LOCK_RW();
+ int rc = rtProcNativeSetPriority(enmPriority);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Update the priority of existing thread.
+ */
+ rc = RTAvlPVDoWithAll(&g_ThreadTree, true, rtThreadSetPriorityOne, NULL);
+ if (RT_SUCCESS(rc))
+ ASMAtomicXchgSize(&g_enmProcessPriority, enmPriority);
+ else
+ {
+ /*
+ * Failed, restore the priority.
+ */
+ rtProcNativeSetPriority(g_enmProcessPriority);
+ RTAvlPVDoWithAll(&g_ThreadTree, true, rtThreadSetPriorityOne, NULL);
+ }
+ }
+ RT_THREAD_UNLOCK_RW();
+ LogFlow(("rtThreadDoSetProcPriority: returns %Rrc\n", rc));
+ return rc;
+}
+
+
+/**
+ * Change the thread state to blocking.
+ *
+ * @param hThread The current thread.
+ * @param enmState The sleep state.
+ * @param fReallySleeping Really going to sleep now.
+ */
+RTDECL(void) RTThreadBlocking(RTTHREAD hThread, RTTHREADSTATE enmState, bool fReallySleeping)
+{
+ Assert(RTTHREAD_IS_SLEEPING(enmState));
+ PRTTHREADINT pThread = hThread;
+ if (pThread != NIL_RTTHREAD)
+ {
+ Assert(pThread == RTThreadSelf());
+ if (rtThreadGetState(pThread) == RTTHREADSTATE_RUNNING)
+ rtThreadSetState(pThread, enmState);
+ ASMAtomicWriteBool(&pThread->fReallySleeping, fReallySleeping);
+ }
+}
+RT_EXPORT_SYMBOL(RTThreadBlocking);
+
+
+/**
+ * Unblocks a thread.
+ *
+ * This function is paired with rtThreadBlocking.
+ *
+ * @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)
+{
+ PRTTHREADINT pThread = hThread;
+ if (pThread != NIL_RTTHREAD)
+ {
+ Assert(pThread == RTThreadSelf());
+ ASMAtomicWriteBool(&pThread->fReallySleeping, false);
+
+ RTTHREADSTATE enmActualState = rtThreadGetState(pThread);
+ if (enmActualState == enmCurState)
+ {
+ rtThreadSetState(pThread, RTTHREADSTATE_RUNNING);
+ if ( pThread->LockValidator.pRec
+ && pThread->LockValidator.enmRecState == enmCurState)
+ ASMAtomicWriteNullPtr(&pThread->LockValidator.pRec);
+ }
+ /* This is a bit ugly... :-/ */
+ else if ( ( enmActualState == RTTHREADSTATE_TERMINATED
+ || enmActualState == RTTHREADSTATE_INITIALIZING)
+ && pThread->LockValidator.pRec)
+ ASMAtomicWriteNullPtr(&pThread->LockValidator.pRec);
+ Assert( pThread->LockValidator.pRec == NULL
+ || RTTHREAD_IS_SLEEPING(enmActualState));
+ }
+}
+RT_EXPORT_SYMBOL(RTThreadUnblocked);
+
+
+/**
+ * Get the current thread state.
+ *
+ * @returns The thread state.
+ * @param hThread The thread.
+ */
+RTDECL(RTTHREADSTATE) RTThreadGetState(RTTHREAD hThread)
+{
+ RTTHREADSTATE enmState = RTTHREADSTATE_INVALID;
+ PRTTHREADINT pThread = rtThreadGet(hThread);
+ if (pThread)
+ {
+ enmState = rtThreadGetState(pThread);
+ rtThreadRelease(pThread);
+ }
+ return enmState;
+}
+RT_EXPORT_SYMBOL(RTThreadGetState);
+
+
+RTDECL(RTTHREADSTATE) RTThreadGetReallySleeping(RTTHREAD hThread)
+{
+ RTTHREADSTATE enmState = RTTHREADSTATE_INVALID;
+ PRTTHREADINT pThread = rtThreadGet(hThread);
+ if (pThread)
+ {
+ enmState = rtThreadGetState(pThread);
+ if (!ASMAtomicUoReadBool(&pThread->fReallySleeping))
+ enmState = RTTHREADSTATE_RUNNING;
+ rtThreadRelease(pThread);
+ }
+ return enmState;
+}
+RT_EXPORT_SYMBOL(RTThreadGetReallySleeping);
+
+
+/**
+ * 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)
+{
+ switch (enmState)
+ {
+ case RTTHREADSTATE_INVALID: return "INVALID";
+ case RTTHREADSTATE_INITIALIZING: return "INITIALIZING";
+ case RTTHREADSTATE_TERMINATED: return "TERMINATED";
+ case RTTHREADSTATE_RUNNING: return "RUNNING";
+ case RTTHREADSTATE_CRITSECT: return "CRITSECT";
+ case RTTHREADSTATE_EVENT: return "EVENT";
+ case RTTHREADSTATE_EVENT_MULTI: return "EVENT_MULTI";
+ case RTTHREADSTATE_FAST_MUTEX: return "FAST_MUTEX";
+ case RTTHREADSTATE_MUTEX: return "MUTEX";
+ case RTTHREADSTATE_RW_READ: return "RW_READ";
+ case RTTHREADSTATE_RW_WRITE: return "RW_WRITE";
+ case RTTHREADSTATE_SLEEP: return "SLEEP";
+ case RTTHREADSTATE_SPIN_MUTEX: return "SPIN_MUTEX";
+ default: return "UnknownThreadState";
+ }
+}
+RT_EXPORT_SYMBOL(RTThreadStateName);
+
+#endif /* IN_RING3 */
+#ifdef IPRT_WITH_GENERIC_TLS
+
+/**
+ * Thread enumerator - clears a TLS entry.
+ *
+ * @returns 0.
+ * @param pNode The thread node.
+ * @param pvUser The TLS index.
+ */
+static DECLCALLBACK(int) rtThreadClearTlsEntryCallback(PAVLPVNODECORE pNode, void *pvUser)
+{
+ PRTTHREADINT pThread = (PRTTHREADINT)pNode;
+ RTTLS iTls = (RTTLS)(uintptr_t)pvUser;
+ ASMAtomicWriteNullPtr(&pThread->apvTlsEntries[iTls]);
+ return 0;
+}
+
+
+/**
+ * Helper for the generic TLS implementation that clears a given TLS
+ * entry on all threads.
+ *
+ * @param iTls The TLS entry. (valid)
+ */
+DECLHIDDEN(void) rtThreadClearTlsEntry(RTTLS iTls)
+{
+ RT_THREAD_LOCK_RD();
+ RTAvlPVDoWithAll(&g_ThreadTree, true /* fFromLeft*/, rtThreadClearTlsEntryCallback, (void *)(uintptr_t)iTls);
+ RT_THREAD_UNLOCK_RD();
+}
+
+#endif /* IPRT_WITH_GENERIC_TLS */
+
+
+#if defined(RT_OS_WINDOWS) && defined(IN_RING3)
+
+/**
+ * Thread enumeration callback for RTThreadNameThreads
+ */
+static DECLCALLBACK(int) rtThreadNameThreadCallback(PAVLPVNODECORE pNode, void *pvUser)
+{
+ PRTTHREADINT pThread = (PRTTHREADINT)pNode;
+ rtThreadNativeInformDebugger(pThread);
+ RT_NOREF_PV(pvUser);
+ return 0;
+}
+
+/**
+ * A function that can be called from the windows debugger to get the names of
+ * all threads when attaching to a process.
+ *
+ * Usage: .call VBoxRT!RTThreadNameThreads()
+ *
+ * @returns 0
+ * @remarks Do not call from source code as it skips locks.
+ */
+extern "C" RTDECL(int) RTThreadNameThreads(void);
+RTDECL(int) RTThreadNameThreads(void)
+{
+ return RTAvlPVDoWithAll(&g_ThreadTree, true /* fFromLeft*/, rtThreadNameThreadCallback, NULL);
+}
+
+#endif
--- /dev/null
+/* $Id: RTStrCopy.cpp $ */
+/** @file
+ * IPRT - RTStrCopy.
+ */
+
+/*
+ * Copyright (C) 2010-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/string.h>
+#include "internal/iprt.h"
+
+
+RTDECL(int) RTStrCopy(char *pszDst, size_t cbDst, const char *pszSrc)
+{
+ size_t cchSrc = strlen(pszSrc);
+ if (RT_LIKELY(cchSrc < cbDst))
+ {
+ memcpy(pszDst, pszSrc, cchSrc + 1);
+ return VINF_SUCCESS;
+ }
+
+ if (cbDst != 0)
+ {
+ memcpy(pszDst, pszSrc, cbDst - 1);
+ pszDst[cbDst - 1] = '\0';
+ }
+ return VERR_BUFFER_OVERFLOW;
+}
+RT_EXPORT_SYMBOL(RTStrCopy);
+
--- /dev/null
+/* $Id: RTStrCopyEx.cpp $ */
+/** @file
+ * IPRT - RTStrCopyEx.
+ */
+
+/*
+ * Copyright (C) 2010-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/string.h>
+#include "internal/iprt.h"
+
+
+RTDECL(int) RTStrCopyEx(char *pszDst, size_t cbDst, const char *pszSrc, size_t cchMaxSrc)
+{
+ const char *pszSrcEol = RTStrEnd(pszSrc, cchMaxSrc);
+ size_t cchSrc = pszSrcEol ? (size_t)(pszSrcEol - pszSrc) : cchMaxSrc;
+ if (RT_LIKELY(cchSrc < cbDst))
+ {
+ memcpy(pszDst, pszSrc, cchSrc);
+ pszDst[cchSrc] = '\0';
+ return VINF_SUCCESS;
+ }
+
+ if (cbDst != 0)
+ {
+ memcpy(pszDst, pszSrc, cbDst - 1);
+ pszDst[cbDst - 1] = '\0';
+ }
+ return VERR_BUFFER_OVERFLOW;
+}
+RT_EXPORT_SYMBOL(RTStrCopyEx);
+
--- /dev/null
+/* $Id: RTStrCopyP.cpp $ */
+/** @file
+ * IPRT - RTStrCopyP.
+ */
+
+/*
+ * Copyright (C) 2010-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/string.h>
+#include "internal/iprt.h"
+
+
+RTDECL(int) RTStrCopyP(char **ppszDst, size_t *pcbDst, const char *pszSrc)
+{
+ size_t const cchSrc = strlen(pszSrc);
+ size_t const cbDst = *pcbDst;
+ char *pszDst = *ppszDst;
+ if (RT_LIKELY(cchSrc < cbDst))
+ {
+ memcpy(pszDst, pszSrc, cchSrc + 1);
+ *ppszDst = pszDst += cchSrc;
+ *pcbDst -= cchSrc;
+ return VINF_SUCCESS;
+ }
+
+ if (cbDst != 0)
+ {
+ memcpy(*ppszDst, pszSrc, cbDst - 1);
+ *ppszDst = pszDst += cbDst - 1;
+ *pszDst = '\0';
+ *pcbDst = 1;
+ }
+ return VERR_BUFFER_OVERFLOW;
+}
+RT_EXPORT_SYMBOL(RTStrCopyP);
+
--- /dev/null
+/* $Id: strformat.cpp $ */
+/** @file
+ * IPRT - String Formatter.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Defined Constants *
+*********************************************************************************************************************************/
+#define ISDIGIT(c) ((c) >= '0' && (c) <= '9')
+/*#define MAX(a, b) ((a) >= (b) ? (a) : (b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b)) */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP RTLOGGROUP_STRING
+#include <iprt/string.h>
+#include "internal/iprt.h"
+
+#include <iprt/assert.h>
+#ifdef IN_RING3
+# include <iprt/alloc.h>
+# include <iprt/err.h>
+# include <iprt/uni.h>
+#endif
+#include <iprt/string.h>
+#include <iprt/stdarg.h>
+#include "internal/string.h"
+
+/* Wrappers for converting to iprt facilities. */
+#define SSToDS(ptr) ptr
+#define kASSERT Assert
+#define KENDIAN_LITTLE 1
+#define KENDIAN KENDIAN_LITTLE
+#define KSIZE size_t
+typedef struct
+{
+ uint32_t ulLo;
+ uint32_t ulHi;
+} KSIZE64;
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+static unsigned _strnlen(const char *psz, unsigned cchMax);
+static unsigned _strnlenUtf16(PCRTUTF16 pwsz, unsigned cchMax);
+static int rtStrFormatNumber(char *psz, KSIZE64 ullValue, unsigned int uiBase, signed int cchWidth, signed int cchPrecision, unsigned int fFlags);
+
+
+/**
+ * Finds the length of a string up to cchMax.
+ * @returns Length.
+ * @param psz Pointer to string.
+ * @param cchMax Max length.
+ */
+static unsigned _strnlen(const char *psz, unsigned cchMax)
+{
+ const char *pszC = psz;
+
+ while (cchMax-- > 0 && *psz != '\0')
+ psz++;
+
+ return (unsigned)(psz - pszC);
+}
+
+
+/**
+ * Finds the length of a string up to cchMax.
+ * @returns Length.
+ * @param pwsz Pointer to string.
+ * @param cchMax Max length.
+ */
+static unsigned _strnlenUtf16(PCRTUTF16 pwsz, unsigned cchMax)
+{
+#ifdef IN_RING3
+ unsigned cwc = 0;
+ while (cchMax-- > 0)
+ {
+ RTUNICP cp;
+ int rc = RTUtf16GetCpEx(&pwsz, &cp);
+ AssertRC(rc);
+ if (RT_FAILURE(rc) || !cp)
+ break;
+ cwc++;
+ }
+ return cwc;
+#else /* !IN_RING3 */
+ PCRTUTF16 pwszC = pwsz;
+
+ while (cchMax-- > 0 && *pwsz != '\0')
+ pwsz++;
+
+ return (unsigned)(pwsz - pwszC);
+#endif /* !IN_RING3 */
+}
+
+
+/**
+ * Finds the length of a string up to cchMax.
+ * @returns Length.
+ * @param pusz Pointer to string.
+ * @param cchMax Max length.
+ */
+static unsigned _strnlenUni(PCRTUNICP pusz, unsigned cchMax)
+{
+ PCRTUNICP puszC = pusz;
+
+ while (cchMax-- > 0 && *pusz != '\0')
+ pusz++;
+
+ return (unsigned)(pusz - puszC);
+}
+
+
+/**
+ * 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 (NTFS_*).
+ */
+RTDECL(int) RTStrFormatNumber(char *psz, uint64_t u64Value, unsigned int uiBase, signed int cchWidth, signed int cchPrecision,
+ unsigned int fFlags)
+{
+ return rtStrFormatNumber(psz, *(KSIZE64 *)(void *)&u64Value, uiBase, cchWidth, cchPrecision, fFlags);
+}
+RT_EXPORT_SYMBOL(RTStrFormatNumber);
+
+
+
+/**
+ * Formats an integer number according to the parameters.
+ *
+ * @returns Length of the number.
+ * @param psz Pointer to output string.
+ * @param ullValue Value. Using the high part is optional.
+ * @param uiBase Number representation base.
+ * @param cchWidth Width
+ * @param cchPrecision Precision.
+ * @param fFlags Flags (NTFS_*).
+ */
+static int rtStrFormatNumber(char *psz, KSIZE64 ullValue, unsigned int uiBase, signed int cchWidth, signed int cchPrecision,
+ unsigned int fFlags)
+{
+ const char *pachDigits = "0123456789abcdef";
+ char *pszStart = psz;
+ int cchMax;
+ int cchValue;
+ unsigned long ul;
+ int i;
+ int j;
+
+ /*
+ * Validate and adjust input...
+ */
+ Assert(uiBase >= 2 && uiBase <= 16);
+ if (fFlags & RTSTR_F_CAPITAL)
+ pachDigits = "0123456789ABCDEF";
+ if (fFlags & RTSTR_F_LEFT)
+ fFlags &= ~RTSTR_F_ZEROPAD;
+ if ( (fFlags & RTSTR_F_THOUSAND_SEP)
+ && ( uiBase != 10
+ || (fFlags & RTSTR_F_ZEROPAD))) /** @todo implement RTSTR_F_ZEROPAD + RTSTR_F_THOUSAND_SEP. */
+ fFlags &= ~RTSTR_F_THOUSAND_SEP;
+
+ /*
+ * Determine value length
+ */
+ cchValue = 0;
+ if (ullValue.ulHi || (fFlags & RTSTR_F_64BIT))
+ {
+ uint64_t u64 = *(uint64_t *)(void *)&ullValue;
+ if ((fFlags & RTSTR_F_VALSIGNED) && (ullValue.ulHi & 0x80000000))
+ u64 = -(int64_t)u64;
+ do
+ {
+ cchValue++;
+ u64 /= uiBase;
+ } while (u64);
+ }
+ else
+ {
+ ul = (fFlags & RTSTR_F_VALSIGNED) && (ullValue.ulLo & 0x80000000) ? -(int32_t)ullValue.ulLo : ullValue.ulLo;
+ do
+ {
+ cchValue++;
+ ul /= uiBase;
+ } while (ul);
+ }
+ if (fFlags & RTSTR_F_THOUSAND_SEP)
+ {
+ if (cchValue <= 3)
+ fFlags &= ~RTSTR_F_THOUSAND_SEP;
+ else
+ cchValue += cchValue / 3 - (cchValue % 3 == 0);
+ }
+
+ /*
+ * Sign (+/-).
+ */
+ i = 0;
+ if (fFlags & RTSTR_F_VALSIGNED)
+ {
+ if ((ullValue.ulHi || (fFlags & RTSTR_F_64BIT) ? ullValue.ulHi : ullValue.ulLo) & 0x80000000)
+ {
+ ullValue.ulLo = -(int32_t)ullValue.ulLo;
+ if (ullValue.ulHi)
+ ullValue.ulHi = ~ullValue.ulHi;
+ psz[i++] = '-';
+ }
+ else if (fFlags & (RTSTR_F_PLUS | RTSTR_F_BLANK))
+ psz[i++] = (char)(fFlags & RTSTR_F_PLUS ? '+' : ' ');
+ }
+
+ /*
+ * Special (0/0x).
+ */
+ if ((fFlags & RTSTR_F_SPECIAL) && (uiBase % 8) == 0)
+ {
+ psz[i++] = '0';
+ if (uiBase == 16)
+ psz[i++] = (char)(fFlags & RTSTR_F_CAPITAL ? 'X' : 'x');
+ }
+
+ /*
+ * width - only if ZEROPAD
+ */
+ cchMax = 64 - (cchValue + i + 1); /* HACK! 64 bytes seems to be the usual buffer size... */
+ cchWidth -= i + cchValue;
+ if (fFlags & RTSTR_F_ZEROPAD)
+ while (--cchWidth >= 0 && i < cchMax)
+ {
+ AssertBreak(i < cchMax);
+ psz[i++] = '0';
+ cchPrecision--;
+ }
+ else if (!(fFlags & RTSTR_F_LEFT) && cchWidth > 0)
+ {
+ AssertStmt(cchWidth < cchMax, cchWidth = cchMax - 1);
+ for (j = i - 1; j >= 0; j--)
+ psz[cchWidth + j] = psz[j];
+ for (j = 0; j < cchWidth; j++)
+ psz[j] = ' ';
+ i += cchWidth;
+ }
+
+ /*
+ * precision
+ */
+ while (--cchPrecision >= cchValue)
+ {
+ AssertBreak(i < cchMax);
+ psz[i++] = '0';
+ }
+
+ psz += i;
+
+ /*
+ * write number - not good enough but it works
+ */
+ psz += cchValue;
+ i = -1;
+ if (ullValue.ulHi || (fFlags & RTSTR_F_64BIT))
+ {
+ uint64_t u64 = *(uint64_t *)(void *)&ullValue;
+ if (fFlags & RTSTR_F_THOUSAND_SEP)
+ {
+ do
+ {
+ if ((-i - 1) % 4 == 3)
+ psz[i--] = ' ';
+ psz[i--] = pachDigits[u64 % uiBase];
+ u64 /= uiBase;
+ } while (u64);
+ }
+ else
+ {
+ do
+ {
+ psz[i--] = pachDigits[u64 % uiBase];
+ u64 /= uiBase;
+ } while (u64);
+ }
+ }
+ else
+ {
+ ul = (fFlags & RTSTR_F_VALSIGNED) && (ullValue.ulLo & 0x80000000) ? -(int32_t)ullValue.ulLo : ullValue.ulLo;
+ if (fFlags & RTSTR_F_THOUSAND_SEP)
+ {
+ do
+ {
+ if ((-i - 1) % 4 == 3)
+ psz[i--] = ' ';
+ psz[i--] = pachDigits[ul % uiBase];
+ ul /= uiBase;
+ } while (ul);
+ }
+ else
+ {
+ do
+ {
+ psz[i--] = pachDigits[ul % uiBase];
+ ul /= uiBase;
+ } while (ul);
+ }
+ }
+
+ /*
+ * width if RTSTR_F_LEFT
+ */
+ if (fFlags & RTSTR_F_LEFT)
+ while (--cchWidth >= 0)
+ *psz++ = ' ';
+
+ *psz = '\0';
+ return (unsigned)(psz - pszStart);
+}
+
+
+/**
+ * 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 an it's 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 Format string.
+ * @param InArgs Argument list.
+ */
+RTDECL(size_t) RTStrFormatV(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, PFNSTRFORMAT pfnFormat, void *pvArgFormat,
+ const char *pszFormat, va_list InArgs)
+{
+ char szTmp[64]; /* Worker functions assumes 64 byte buffer! Ugly but faster. */
+ va_list args;
+ KSIZE cch = 0;
+ const char *pszStartOutput = pszFormat;
+
+ va_copy(args, InArgs); /* make a copy so we can reference it (AMD64 / gcc). */
+
+ while (*pszFormat != '\0')
+ {
+ if (*pszFormat == '%')
+ {
+ /* output pending string. */
+ if (pszStartOutput != pszFormat)
+ cch += pfnOutput(pvArgOutput, pszStartOutput, pszFormat - pszStartOutput);
+
+ /* skip '%' */
+ pszFormat++;
+ if (*pszFormat == '%') /* '%%'-> '%' */
+ pszStartOutput = pszFormat++;
+ else
+ {
+ unsigned int fFlags = 0;
+ int cchWidth = -1;
+ int cchPrecision = -1;
+ unsigned int uBase = 10;
+ char chArgSize;
+
+ /* flags */
+ for (;;)
+ {
+ switch (*pszFormat++)
+ {
+ case '#': fFlags |= RTSTR_F_SPECIAL; continue;
+ case '-': fFlags |= RTSTR_F_LEFT; continue;
+ case '+': fFlags |= RTSTR_F_PLUS; continue;
+ case ' ': fFlags |= RTSTR_F_BLANK; continue;
+ case '0': fFlags |= RTSTR_F_ZEROPAD; continue;
+ case '\'': fFlags |= RTSTR_F_THOUSAND_SEP; continue;
+ }
+ pszFormat--;
+ break;
+ }
+
+ /* width */
+ if (ISDIGIT(*pszFormat))
+ {
+ for (cchWidth = 0; ISDIGIT(*pszFormat); pszFormat++)
+ {
+ cchWidth *= 10;
+ cchWidth += *pszFormat - '0';
+ }
+ fFlags |= RTSTR_F_WIDTH;
+ }
+ else if (*pszFormat == '*')
+ {
+ pszFormat++;
+ cchWidth = va_arg(args, int);
+ if (cchWidth < 0)
+ {
+ cchWidth = -cchWidth;
+ fFlags |= RTSTR_F_LEFT;
+ }
+ fFlags |= RTSTR_F_WIDTH;
+ }
+
+ /* precision */
+ if (*pszFormat == '.')
+ {
+ pszFormat++;
+ if (ISDIGIT(*pszFormat))
+ {
+ for (cchPrecision = 0; ISDIGIT(*pszFormat); pszFormat++)
+ {
+ cchPrecision *= 10;
+ cchPrecision += *pszFormat - '0';
+ }
+
+ }
+ else if (*pszFormat == '*')
+ {
+ pszFormat++;
+ cchPrecision = va_arg(args, int);
+ }
+ if (cchPrecision < 0)
+ cchPrecision = 0;
+ fFlags |= RTSTR_F_PRECISION;
+ }
+
+ /*
+ * Argument size.
+ */
+ chArgSize = *pszFormat;
+ switch (chArgSize)
+ {
+ default:
+ chArgSize = 0;
+ break;
+
+ case 'z':
+ case 'L':
+ case 'j':
+ case 't':
+ pszFormat++;
+ break;
+
+ case 'l':
+ pszFormat++;
+ if (*pszFormat == 'l')
+ {
+ chArgSize = 'L';
+ pszFormat++;
+ }
+ break;
+
+ case 'h':
+ pszFormat++;
+ if (*pszFormat == 'h')
+ {
+ chArgSize = 'H';
+ pszFormat++;
+ }
+ break;
+
+ case 'I': /* Used by Win32/64 compilers. */
+ if ( pszFormat[1] == '6'
+ && pszFormat[2] == '4')
+ {
+ pszFormat += 3;
+ chArgSize = 'L';
+ }
+ else if ( pszFormat[1] == '3'
+ && pszFormat[2] == '2')
+ {
+ pszFormat += 3;
+ chArgSize = 0;
+ }
+ else
+ {
+ pszFormat += 1;
+ chArgSize = 'j';
+ }
+ break;
+
+ case 'q': /* Used on BSD platforms. */
+ pszFormat++;
+ chArgSize = 'L';
+ break;
+ }
+
+ /*
+ * The type.
+ */
+ switch (*pszFormat++)
+ {
+ /* char */
+ case 'c':
+ {
+ if (!(fFlags & RTSTR_F_LEFT))
+ while (--cchWidth > 0)
+ cch += pfnOutput(pvArgOutput, " ", 1);
+
+ szTmp[0] = (char)va_arg(args, int);
+ szTmp[1] = '\0'; /* Some output functions wants terminated strings. */
+ cch += pfnOutput(pvArgOutput, SSToDS(&szTmp[0]), 1);
+
+ while (--cchWidth > 0)
+ cch += pfnOutput(pvArgOutput, " ", 1);
+ break;
+ }
+
+ case 'S': /* Legacy, conversion done by streams now. */
+ case 's':
+ {
+ if (chArgSize == 'l')
+ {
+ /* utf-16 -> utf-8 */
+ int cchStr;
+ PCRTUTF16 pwszStr = va_arg(args, PRTUTF16);
+
+ if (!VALID_PTR(pwszStr))
+ {
+ static RTUTF16 s_wszNull[] = {'<', 'N', 'U', 'L', 'L', '>', '\0' };
+ pwszStr = s_wszNull;
+ }
+ cchStr = _strnlenUtf16(pwszStr, (unsigned)cchPrecision);
+ if (!(fFlags & RTSTR_F_LEFT))
+ while (--cchWidth >= cchStr)
+ cch += pfnOutput(pvArgOutput, " ", 1);
+ cchWidth -= cchStr;
+ while (cchStr-- > 0)
+ {
+/** @todo \#ifndef IN_RC*/
+#ifdef IN_RING3
+ RTUNICP Cp;
+ RTUtf16GetCpEx(&pwszStr, &Cp);
+ char *pszEnd = RTStrPutCp(szTmp, Cp);
+ *pszEnd = '\0';
+ cch += pfnOutput(pvArgOutput, szTmp, pszEnd - szTmp);
+#else
+ char ch = (char)*pwszStr++;
+ cch += pfnOutput(pvArgOutput, &ch, 1);
+#endif
+ }
+ while (--cchWidth >= 0)
+ cch += pfnOutput(pvArgOutput, " ", 1);
+ }
+ else if (chArgSize == 'L')
+ {
+ /* unicp -> utf8 */
+ int cchStr;
+ PCRTUNICP puszStr = va_arg(args, PCRTUNICP);
+
+ if (!VALID_PTR(puszStr))
+ {
+ static RTUNICP s_uszNull[] = {'<', 'N', 'U', 'L', 'L', '>', '\0' };
+ puszStr = s_uszNull;
+ }
+ cchStr = _strnlenUni(puszStr, (unsigned)cchPrecision);
+ if (!(fFlags & RTSTR_F_LEFT))
+ while (--cchWidth >= cchStr)
+ cch += pfnOutput(pvArgOutput, " ", 1);
+
+ cchWidth -= cchStr;
+ while (cchStr-- > 0)
+ {
+/** @todo \#ifndef IN_RC*/
+#ifdef IN_RING3
+ char *pszEnd = RTStrPutCp(szTmp, *puszStr++);
+ cch += pfnOutput(pvArgOutput, szTmp, pszEnd - szTmp);
+#else
+ char ch = (char)*puszStr++;
+ cch += pfnOutput(pvArgOutput, &ch, 1);
+#endif
+ }
+ while (--cchWidth >= 0)
+ cch += pfnOutput(pvArgOutput, " ", 1);
+ }
+ else
+ {
+ int cchStr;
+ const char *pszStr = va_arg(args, char*);
+
+ if (!VALID_PTR(pszStr))
+ pszStr = "<NULL>";
+ cchStr = _strnlen(pszStr, (unsigned)cchPrecision);
+ if (!(fFlags & RTSTR_F_LEFT))
+ while (--cchWidth >= cchStr)
+ cch += pfnOutput(pvArgOutput, " ", 1);
+
+ cch += pfnOutput(pvArgOutput, pszStr, cchStr);
+
+ while (--cchWidth >= cchStr)
+ cch += pfnOutput(pvArgOutput, " ", 1);
+ }
+ break;
+ }
+
+ /*-----------------*/
+ /* integer/pointer */
+ /*-----------------*/
+ case 'd':
+ case 'i':
+ case 'o':
+ case 'p':
+ case 'u':
+ case 'x':
+ case 'X':
+ {
+ int cchNum;
+ uint64_t u64Value;
+
+ switch (pszFormat[-1])
+ {
+ case 'd': /* signed decimal integer */
+ case 'i':
+ fFlags |= RTSTR_F_VALSIGNED;
+ break;
+
+ case 'o':
+ uBase = 8;
+ break;
+
+ case 'p':
+ fFlags |= RTSTR_F_ZEROPAD; /* Note not standard behaviour (but I like it this way!) */
+ uBase = 16;
+ if (cchWidth < 0)
+ cchWidth = sizeof(char *) * 2;
+ break;
+
+ case 'u':
+ uBase = 10;
+ break;
+
+ case 'X':
+ fFlags |= RTSTR_F_CAPITAL;
+ /* fall thru */
+ case 'x':
+ uBase = 16;
+ break;
+ }
+
+ if (pszFormat[-1] == 'p')
+ u64Value = va_arg(args, uintptr_t);
+ else if (fFlags & RTSTR_F_VALSIGNED)
+ {
+ if (chArgSize == 'L')
+ {
+ u64Value = va_arg(args, int64_t);
+ fFlags |= RTSTR_F_64BIT;
+ }
+ else if (chArgSize == 'l')
+ {
+ u64Value = va_arg(args, signed long);
+ fFlags |= RTSTR_GET_BIT_FLAG(unsigned long);
+ }
+ else if (chArgSize == 'h')
+ {
+ u64Value = va_arg(args, /* signed short */ int);
+ fFlags |= RTSTR_GET_BIT_FLAG(signed short);
+ }
+ else if (chArgSize == 'H')
+ {
+ u64Value = va_arg(args, /* int8_t */ int);
+ fFlags |= RTSTR_GET_BIT_FLAG(int8_t);
+ }
+ else if (chArgSize == 'j')
+ {
+ u64Value = va_arg(args, /*intmax_t*/ int64_t);
+ fFlags |= RTSTR_F_64BIT;
+ }
+ else if (chArgSize == 'z')
+ {
+ u64Value = va_arg(args, size_t);
+ fFlags |= RTSTR_GET_BIT_FLAG(size_t);
+ }
+ else if (chArgSize == 't')
+ {
+ u64Value = va_arg(args, ptrdiff_t);
+ fFlags |= RTSTR_GET_BIT_FLAG(ptrdiff_t);
+ }
+ else
+ {
+ u64Value = va_arg(args, signed int);
+ fFlags |= RTSTR_GET_BIT_FLAG(signed int);
+ }
+ }
+ else
+ {
+ if (chArgSize == 'L')
+ {
+ u64Value = va_arg(args, uint64_t);
+ fFlags |= RTSTR_F_64BIT;
+ }
+ else if (chArgSize == 'l')
+ {
+ u64Value = va_arg(args, unsigned long);
+ fFlags |= RTSTR_GET_BIT_FLAG(unsigned long);
+ }
+ else if (chArgSize == 'h')
+ {
+ u64Value = va_arg(args, /* unsigned short */ int);
+ fFlags |= RTSTR_GET_BIT_FLAG(unsigned short);
+ }
+ else if (chArgSize == 'H')
+ {
+ u64Value = va_arg(args, /* uint8_t */ int);
+ fFlags |= RTSTR_GET_BIT_FLAG(uint8_t);
+ }
+ else if (chArgSize == 'j')
+ {
+ u64Value = va_arg(args, /*uintmax_t*/ int64_t);
+ fFlags |= RTSTR_F_64BIT;
+ }
+ else if (chArgSize == 'z')
+ {
+ u64Value = va_arg(args, size_t);
+ fFlags |= RTSTR_GET_BIT_FLAG(size_t);
+ }
+ else if (chArgSize == 't')
+ {
+ u64Value = va_arg(args, ptrdiff_t);
+ fFlags |= RTSTR_GET_BIT_FLAG(ptrdiff_t);
+ }
+ else
+ {
+ u64Value = va_arg(args, unsigned int);
+ fFlags |= RTSTR_GET_BIT_FLAG(unsigned int);
+ }
+ }
+ cchNum = RTStrFormatNumber((char *)SSToDS(&szTmp), u64Value, uBase, cchWidth, cchPrecision, fFlags);
+ cch += pfnOutput(pvArgOutput, (char *)SSToDS(&szTmp), cchNum);
+ break;
+ }
+
+ /*
+ * Nested extensions.
+ */
+ case 'M': /* replace the format string (not stacked yet). */
+ {
+ pszStartOutput = pszFormat = va_arg(args, const char *);
+ AssertPtr(pszStartOutput);
+ break;
+ }
+
+ case 'N': /* real nesting. */
+ {
+ const char *pszFormatNested = va_arg(args, const char *);
+ va_list *pArgsNested = va_arg(args, va_list *);
+ va_list ArgsNested;
+ va_copy(ArgsNested, *pArgsNested);
+ Assert(pszFormatNested);
+ cch += RTStrFormatV(pfnOutput, pvArgOutput, pfnFormat, pvArgFormat, pszFormatNested, ArgsNested);
+ va_end(ArgsNested);
+ break;
+ }
+
+ /*
+ * IPRT Extensions.
+ */
+ case 'R':
+ {
+ if (*pszFormat != '[')
+ {
+ pszFormat--;
+ cch += rtstrFormatRt(pfnOutput, pvArgOutput, &pszFormat, &args, cchWidth, cchPrecision, fFlags, chArgSize);
+ }
+ else
+ {
+ pszFormat--;
+ cch += rtstrFormatType(pfnOutput, pvArgOutput, &pszFormat, &args, cchWidth, cchPrecision, fFlags, chArgSize);
+ }
+ break;
+ }
+
+ /*
+ * Custom format.
+ */
+ default:
+ {
+ if (pfnFormat)
+ {
+ pszFormat--;
+ cch += pfnFormat(pvArgFormat, pfnOutput, pvArgOutput, &pszFormat, &args, cchWidth, cchPrecision, fFlags, chArgSize);
+ }
+ break;
+ }
+ }
+ pszStartOutput = pszFormat;
+ }
+ }
+ else
+ pszFormat++;
+ }
+
+ /* output pending string. */
+ if (pszStartOutput != pszFormat)
+ cch += pfnOutput(pvArgOutput, pszStartOutput, pszFormat - pszStartOutput);
+
+ /* terminate the output */
+ pfnOutput(pvArgOutput, NULL, 0);
+
+ return cch;
+}
+RT_EXPORT_SYMBOL(RTStrFormatV);
+
+
+/**
+ * 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 an it's 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 Format string.
+ * @param ... Argument list.
+ */
+RTDECL(size_t) RTStrFormat(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, PFNSTRFORMAT pfnFormat, void *pvArgFormat, const char *pszFormat, ...)
+{
+ size_t cch;
+ va_list args;
+ va_start(args, pszFormat);
+ cch = RTStrFormatV(pfnOutput, pvArgOutput, pfnFormat, pvArgFormat, pszFormat, args);
+ va_end(args);
+ return cch;
+}
+RT_EXPORT_SYMBOL(RTStrFormat);
+
--- /dev/null
+/* $Id: strformatrt.cpp $ */
+/** @file
+ * IPRT - IPRT String Formatter Extensions.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP RTLOGGROUP_STRING
+#include <iprt/string.h>
+#ifndef RT_NO_EXPORT_SYMBOL
+# define RT_NO_EXPORT_SYMBOL /* don't slurp <linux/module.h> which then again
+ slurps arch-specific headers defining symbols */
+#endif
+#include "internal/iprt.h"
+
+#include <iprt/log.h>
+#include <iprt/assert.h>
+#include <iprt/string.h>
+#include <iprt/stdarg.h>
+#ifdef IN_RING3
+# include <iprt/thread.h>
+# include <iprt/err.h>
+#endif
+#include <iprt/ctype.h>
+#include <iprt/time.h>
+#include <iprt/net.h>
+#include <iprt/path.h>
+#include <iprt/asm.h>
+#define STRFORMAT_WITH_X86
+#ifdef STRFORMAT_WITH_X86
+# include <iprt/x86.h>
+#endif
+#include "internal/string.h"
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+static char g_szHexDigits[17] = "0123456789abcdef";
+
+
+/**
+ * Helper that formats a 16-bit hex word in a IPv6 address.
+ *
+ * @returns Length in chars.
+ * @param pszDst The output buffer. Written from the start.
+ * @param uWord The word to format as hex.
+ */
+static size_t rtstrFormatIPv6HexWord(char *pszDst, uint16_t uWord)
+{
+ size_t off;
+ uint16_t cDigits;
+
+ if (uWord & UINT16_C(0xff00))
+ cDigits = uWord & UINT16_C(0xf000) ? 4 : 3;
+ else
+ cDigits = uWord & UINT16_C(0x00f0) ? 2 : 1;
+
+ off = 0;
+ switch (cDigits)
+ {
+ case 4: pszDst[off++] = g_szHexDigits[(uWord >> 12) & 0xf]; /* fall thru */
+ case 3: pszDst[off++] = g_szHexDigits[(uWord >> 8) & 0xf]; /* fall thru */
+ case 2: pszDst[off++] = g_szHexDigits[(uWord >> 4) & 0xf]; /* fall thru */
+ case 1: pszDst[off++] = g_szHexDigits[(uWord >> 0) & 0xf];
+ break;
+ }
+ pszDst[off] = '\0';
+ return off;
+}
+
+
+/**
+ * Helper function to format IPv6 address according to RFC 5952.
+ *
+ * @returns The number of bytes formatted.
+ * @param pfnOutput Pointer to output function.
+ * @param pvArgOutput Argument for the output function.
+ * @param pIpv6Addr IPv6 address
+ */
+static size_t rtstrFormatIPv6(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, PCRTNETADDRIPV6 pIpv6Addr)
+{
+ size_t cch; /* result */
+ bool fEmbeddedIpv4;
+ size_t cwHexPart;
+ size_t cwLongestZeroRun;
+ size_t iLongestZeroStart;
+ size_t idx;
+ char szHexWord[8];
+
+ Assert(pIpv6Addr != NULL);
+
+ /*
+ * Check for embedded IPv4 address.
+ *
+ * IPv4-compatible - ::11.22.33.44 (obsolete)
+ * IPv4-mapped - ::ffff:11.22.33.44
+ * IPv4-translated - ::ffff:0:11.22.33.44 (RFC 2765)
+ */
+ fEmbeddedIpv4 = false;
+ cwHexPart = RT_ELEMENTS(pIpv6Addr->au16);
+ if ( pIpv6Addr->au64[0] == 0
+ && ( ( pIpv6Addr->au32[2] == 0
+ && pIpv6Addr->au32[3] != 0
+ && pIpv6Addr->au32[3] != RT_H2BE_U32_C(1) )
+ || pIpv6Addr->au32[2] == RT_H2BE_U32_C(0x0000ffff)
+ || pIpv6Addr->au32[2] == RT_H2BE_U32_C(0xffff0000) ) )
+ {
+ fEmbeddedIpv4 = true;
+ cwHexPart -= 2;
+ }
+
+ /*
+ * Find the longest sequences of two or more zero words.
+ */
+ cwLongestZeroRun = 0;
+ iLongestZeroStart = 0;
+ for (idx = 0; idx < cwHexPart; idx++)
+ if (pIpv6Addr->au16[idx] == 0)
+ {
+ size_t iZeroStart = idx;
+ size_t cwZeroRun;
+ do
+ idx++;
+ while (idx < cwHexPart && pIpv6Addr->au16[idx] == 0);
+ cwZeroRun = idx - iZeroStart;
+ if (cwZeroRun > 1 && cwZeroRun > cwLongestZeroRun)
+ {
+ cwLongestZeroRun = cwZeroRun;
+ iLongestZeroStart = iZeroStart;
+ if (cwZeroRun >= cwHexPart - idx)
+ break;
+ }
+ }
+
+ /*
+ * Do the formatting.
+ */
+ cch = 0;
+ if (cwLongestZeroRun == 0)
+ {
+ for (idx = 0; idx < cwHexPart; ++idx)
+ {
+ if (idx > 0)
+ cch += pfnOutput(pvArgOutput, ":", 1);
+ cch += pfnOutput(pvArgOutput, szHexWord, rtstrFormatIPv6HexWord(szHexWord, RT_BE2H_U16(pIpv6Addr->au16[idx])));
+ }
+
+ if (fEmbeddedIpv4)
+ cch += pfnOutput(pvArgOutput, ":", 1);
+ }
+ else
+ {
+ const size_t iLongestZeroEnd = iLongestZeroStart + cwLongestZeroRun;
+
+ if (iLongestZeroStart == 0)
+ cch += pfnOutput(pvArgOutput, ":", 1);
+ else
+ for (idx = 0; idx < iLongestZeroStart; ++idx)
+ {
+ cch += pfnOutput(pvArgOutput, szHexWord, rtstrFormatIPv6HexWord(szHexWord, RT_BE2H_U16(pIpv6Addr->au16[idx])));
+ cch += pfnOutput(pvArgOutput, ":", 1);
+ }
+
+ if (iLongestZeroEnd == cwHexPart)
+ cch += pfnOutput(pvArgOutput, ":", 1);
+ else
+ {
+ for (idx = iLongestZeroEnd; idx < cwHexPart; ++idx)
+ {
+ cch += pfnOutput(pvArgOutput, ":", 1);
+ cch += pfnOutput(pvArgOutput, szHexWord, rtstrFormatIPv6HexWord(szHexWord, RT_BE2H_U16(pIpv6Addr->au16[idx])));
+ }
+
+ if (fEmbeddedIpv4)
+ cch += pfnOutput(pvArgOutput, ":", 1);
+ }
+ }
+
+ if (fEmbeddedIpv4)
+ cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
+ "%u.%u.%u.%u",
+ pIpv6Addr->au8[12],
+ pIpv6Addr->au8[13],
+ pIpv6Addr->au8[14],
+ pIpv6Addr->au8[15]);
+
+ return cch;
+}
+
+
+/**
+ * Callback to format iprt formatting extentions.
+ * See @ref pg_rt_str_format for a reference on the format types.
+ *
+ * @returns The number of bytes formatted.
+ * @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'.
+ */
+DECLHIDDEN(size_t) rtstrFormatRt(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, const char **ppszFormat, va_list *pArgs,
+ int cchWidth, int cchPrecision, unsigned fFlags, char chArgSize)
+{
+ const char *pszFormatOrg = *ppszFormat;
+ char ch = *(*ppszFormat)++;
+ size_t cch;
+ char szBuf[80];
+
+ if (ch == 'R')
+ {
+ ch = *(*ppszFormat)++;
+ switch (ch)
+ {
+ /*
+ * Groups 1 and 2.
+ */
+ case 'T':
+ case 'G':
+ case 'H':
+ case 'R':
+ case 'C':
+ case 'I':
+ case 'X':
+ case 'U':
+ case 'K':
+ {
+ /*
+ * Interpret the type.
+ */
+ typedef enum
+ {
+ RTSF_INT,
+ RTSF_INTW,
+ RTSF_BOOL,
+ RTSF_FP16,
+ RTSF_FP32,
+ RTSF_FP64,
+ RTSF_IPV4,
+ RTSF_IPV6,
+ RTSF_MAC,
+ RTSF_NETADDR,
+ RTSF_UUID
+ } RTSF;
+ static const struct
+ {
+ uint8_t cch; /**< the length of the string. */
+ char sz[10]; /**< the part following 'R'. */
+ uint8_t cb; /**< the size of the type. */
+ uint8_t u8Base; /**< the size of the type. */
+ RTSF enmFormat; /**< The way to format it. */
+ uint16_t fFlags; /**< additional RTSTR_F_* flags. */
+ }
+ /** Sorted array of types, looked up using binary search! */
+ s_aTypes[] =
+ {
+#define STRMEM(str) sizeof(str) - 1, str
+ { STRMEM("Ci"), sizeof(RTINT), 10, RTSF_INT, RTSTR_F_VALSIGNED },
+ { STRMEM("Cp"), sizeof(RTCCPHYS), 16, RTSF_INTW, 0 },
+ { STRMEM("Cr"), sizeof(RTCCUINTREG), 16, RTSF_INTW, 0 },
+ { STRMEM("Cu"), sizeof(RTUINT), 10, RTSF_INT, 0 },
+ { STRMEM("Cv"), sizeof(void *), 16, RTSF_INTW, 0 },
+ { STRMEM("Cx"), sizeof(RTUINT), 16, RTSF_INT, 0 },
+ { STRMEM("Gi"), sizeof(RTGCINT), 10, RTSF_INT, RTSTR_F_VALSIGNED },
+ { STRMEM("Gp"), sizeof(RTGCPHYS), 16, RTSF_INTW, 0 },
+ { STRMEM("Gr"), sizeof(RTGCUINTREG), 16, RTSF_INTW, 0 },
+ { STRMEM("Gu"), sizeof(RTGCUINT), 10, RTSF_INT, 0 },
+ { STRMEM("Gv"), sizeof(RTGCPTR), 16, RTSF_INTW, 0 },
+ { STRMEM("Gx"), sizeof(RTGCUINT), 16, RTSF_INT, 0 },
+ { STRMEM("Hi"), sizeof(RTHCINT), 10, RTSF_INT, RTSTR_F_VALSIGNED },
+ { STRMEM("Hp"), sizeof(RTHCPHYS), 16, RTSF_INTW, 0 },
+ { STRMEM("Hr"), sizeof(RTHCUINTREG), 16, RTSF_INTW, 0 },
+ { STRMEM("Hu"), sizeof(RTHCUINT), 10, RTSF_INT, 0 },
+ { STRMEM("Hv"), sizeof(RTHCPTR), 16, RTSF_INTW, 0 },
+ { STRMEM("Hx"), sizeof(RTHCUINT), 16, RTSF_INT, 0 },
+ { STRMEM("I16"), sizeof(int16_t), 10, RTSF_INT, RTSTR_F_VALSIGNED },
+ { STRMEM("I32"), sizeof(int32_t), 10, RTSF_INT, RTSTR_F_VALSIGNED },
+ { STRMEM("I64"), sizeof(int64_t), 10, RTSF_INT, RTSTR_F_VALSIGNED },
+ { STRMEM("I8"), sizeof(int8_t), 10, RTSF_INT, RTSTR_F_VALSIGNED },
+ { STRMEM("Kv"), sizeof(RTHCPTR), 16, RTSF_INT, RTSTR_F_OBFUSCATE_PTR },
+ { STRMEM("Rv"), sizeof(RTRCPTR), 16, RTSF_INTW, 0 },
+ { STRMEM("Tbool"), sizeof(bool), 10, RTSF_BOOL, 0 },
+ { STRMEM("Tfile"), sizeof(RTFILE), 10, RTSF_INT, 0 },
+ { STRMEM("Tfmode"), sizeof(RTFMODE), 16, RTSF_INTW, 0 },
+ { STRMEM("Tfoff"), sizeof(RTFOFF), 10, RTSF_INT, RTSTR_F_VALSIGNED },
+ { STRMEM("Tfp16"), sizeof(RTFAR16), 16, RTSF_FP16, RTSTR_F_ZEROPAD },
+ { STRMEM("Tfp32"), sizeof(RTFAR32), 16, RTSF_FP32, RTSTR_F_ZEROPAD },
+ { STRMEM("Tfp64"), sizeof(RTFAR64), 16, RTSF_FP64, RTSTR_F_ZEROPAD },
+ { STRMEM("Tgid"), sizeof(RTGID), 10, RTSF_INT, RTSTR_F_VALSIGNED },
+ { STRMEM("Tino"), sizeof(RTINODE), 16, RTSF_INTW, 0 },
+ { STRMEM("Tint"), sizeof(RTINT), 10, RTSF_INT, RTSTR_F_VALSIGNED },
+ { STRMEM("Tiop"), sizeof(RTIOPORT), 16, RTSF_INTW, 0 },
+ { STRMEM("Tldrm"), sizeof(RTLDRMOD), 16, RTSF_INTW, 0 },
+ { STRMEM("Tmac"), sizeof(PCRTMAC), 16, RTSF_MAC, 0 },
+ { STRMEM("Tnaddr"), sizeof(PCRTNETADDR), 10, RTSF_NETADDR,0 },
+ { STRMEM("Tnaipv4"), sizeof(RTNETADDRIPV4), 10, RTSF_IPV4, 0 },
+ { STRMEM("Tnaipv6"), sizeof(PCRTNETADDRIPV6),16, RTSF_IPV6, 0 },
+ { STRMEM("Tnthrd"), sizeof(RTNATIVETHREAD), 16, RTSF_INTW, 0 },
+ { STRMEM("Tproc"), sizeof(RTPROCESS), 16, RTSF_INTW, 0 },
+ { STRMEM("Tptr"), sizeof(RTUINTPTR), 16, RTSF_INTW, 0 },
+ { STRMEM("Treg"), sizeof(RTCCUINTREG), 16, RTSF_INTW, 0 },
+ { STRMEM("Tsel"), sizeof(RTSEL), 16, RTSF_INTW, 0 },
+ { STRMEM("Tsem"), sizeof(RTSEMEVENT), 16, RTSF_INTW, 0 },
+ { STRMEM("Tsock"), sizeof(RTSOCKET), 10, RTSF_INT, 0 },
+ { STRMEM("Tthrd"), sizeof(RTTHREAD), 16, RTSF_INTW, 0 },
+ { STRMEM("Tuid"), sizeof(RTUID), 10, RTSF_INT, RTSTR_F_VALSIGNED },
+ { STRMEM("Tuint"), sizeof(RTUINT), 10, RTSF_INT, 0 },
+ { STRMEM("Tunicp"), sizeof(RTUNICP), 16, RTSF_INTW, RTSTR_F_ZEROPAD },
+ { STRMEM("Tutf16"), sizeof(RTUTF16), 16, RTSF_INTW, RTSTR_F_ZEROPAD },
+ { STRMEM("Tuuid"), sizeof(PCRTUUID), 16, RTSF_UUID, 0 },
+ { STRMEM("Txint"), sizeof(RTUINT), 16, RTSF_INT, 0 },
+ { STRMEM("U16"), sizeof(uint16_t), 10, RTSF_INT, 0 },
+ { STRMEM("U32"), sizeof(uint32_t), 10, RTSF_INT, 0 },
+ { STRMEM("U64"), sizeof(uint64_t), 10, RTSF_INT, 0 },
+ { STRMEM("U8"), sizeof(uint8_t), 10, RTSF_INT, 0 },
+ { STRMEM("X16"), sizeof(uint16_t), 16, RTSF_INT, 0 },
+ { STRMEM("X32"), sizeof(uint32_t), 16, RTSF_INT, 0 },
+ { STRMEM("X64"), sizeof(uint64_t), 16, RTSF_INT, 0 },
+ { STRMEM("X8"), sizeof(uint8_t), 16, RTSF_INT, 0 },
+#undef STRMEM
+ };
+ static const char s_szNull[] = "<NULL>";
+
+ const char *pszType = *ppszFormat - 1;
+ int iStart = 0;
+ int iEnd = RT_ELEMENTS(s_aTypes) - 1;
+ int i = RT_ELEMENTS(s_aTypes) / 2;
+
+ union
+ {
+ uint8_t u8;
+ uint16_t u16;
+ uint32_t u32;
+ uint64_t u64;
+ int8_t i8;
+ int16_t i16;
+ int32_t i32;
+ int64_t i64;
+ RTR0INTPTR uR0Ptr;
+ RTFAR16 fp16;
+ RTFAR32 fp32;
+ RTFAR64 fp64;
+ bool fBool;
+ PCRTMAC pMac;
+ RTNETADDRIPV4 Ipv4Addr;
+ PCRTNETADDRIPV6 pIpv6Addr;
+ PCRTNETADDR pNetAddr;
+ PCRTUUID pUuid;
+ } u;
+
+ AssertMsg(!chArgSize, ("Not argument size '%c' for RT types! '%.10s'\n", chArgSize, pszFormatOrg));
+ RT_NOREF_PV(chArgSize);
+
+ /*
+ * Lookup the type - binary search.
+ */
+ for (;;)
+ {
+ int iDiff = strncmp(pszType, s_aTypes[i].sz, s_aTypes[i].cch);
+ if (!iDiff)
+ break;
+ if (iEnd == iStart)
+ {
+ AssertMsgFailed(("Invalid format type '%.10s'!\n", pszFormatOrg));
+ return 0;
+ }
+ if (iDiff < 0)
+ iEnd = i - 1;
+ else
+ iStart = i + 1;
+ if (iEnd < iStart)
+ {
+ AssertMsgFailed(("Invalid format type '%.10s'!\n", pszFormatOrg));
+ return 0;
+ }
+ i = iStart + (iEnd - iStart) / 2;
+ }
+
+ /*
+ * Advance the format string and merge flags.
+ */
+ *ppszFormat += s_aTypes[i].cch - 1;
+ fFlags |= s_aTypes[i].fFlags;
+
+ /*
+ * Fetch the argument.
+ * It's important that a signed value gets sign-extended up to 64-bit.
+ */
+ RT_ZERO(u);
+ if (fFlags & RTSTR_F_VALSIGNED)
+ {
+ switch (s_aTypes[i].cb)
+ {
+ case sizeof(int8_t):
+ u.i64 = va_arg(*pArgs, /*int8_t*/int);
+ fFlags |= RTSTR_F_8BIT;
+ break;
+ case sizeof(int16_t):
+ u.i64 = va_arg(*pArgs, /*int16_t*/int);
+ fFlags |= RTSTR_F_16BIT;
+ break;
+ case sizeof(int32_t):
+ u.i64 = va_arg(*pArgs, int32_t);
+ fFlags |= RTSTR_F_32BIT;
+ break;
+ case sizeof(int64_t):
+ u.i64 = va_arg(*pArgs, int64_t);
+ fFlags |= RTSTR_F_64BIT;
+ break;
+ default:
+ AssertMsgFailed(("Invalid format error, size %d'!\n", s_aTypes[i].cb));
+ break;
+ }
+ }
+ else
+ {
+ switch (s_aTypes[i].cb)
+ {
+ case sizeof(uint8_t):
+ u.u8 = va_arg(*pArgs, /*uint8_t*/unsigned);
+ fFlags |= RTSTR_F_8BIT;
+ break;
+ case sizeof(uint16_t):
+ u.u16 = va_arg(*pArgs, /*uint16_t*/unsigned);
+ fFlags |= RTSTR_F_16BIT;
+ break;
+ case sizeof(uint32_t):
+ u.u32 = va_arg(*pArgs, uint32_t);
+ fFlags |= RTSTR_F_32BIT;
+ break;
+ case sizeof(uint64_t):
+ u.u64 = va_arg(*pArgs, uint64_t);
+ fFlags |= RTSTR_F_64BIT;
+ break;
+ case sizeof(RTFAR32):
+ u.fp32 = va_arg(*pArgs, RTFAR32);
+ break;
+ case sizeof(RTFAR64):
+ u.fp64 = va_arg(*pArgs, RTFAR64);
+ break;
+ default:
+ AssertMsgFailed(("Invalid format error, size %d'!\n", s_aTypes[i].cb));
+ break;
+ }
+ }
+
+#ifndef DEBUG
+ /*
+ * For now don't show the address.
+ */
+ if (fFlags & RTSTR_F_OBFUSCATE_PTR)
+ {
+ cch = rtStrFormatKernelAddress(szBuf, sizeof(szBuf), u.uR0Ptr, cchWidth, cchPrecision, fFlags);
+ return pfnOutput(pvArgOutput, szBuf, cch);
+ }
+#endif
+
+ /*
+ * Format the output.
+ */
+ switch (s_aTypes[i].enmFormat)
+ {
+ case RTSF_INT:
+ {
+ cch = RTStrFormatNumber(szBuf, u.u64, s_aTypes[i].u8Base, cchWidth, cchPrecision, fFlags);
+ break;
+ }
+
+ /* hex which defaults to max width. */
+ case RTSF_INTW:
+ {
+ Assert(s_aTypes[i].u8Base == 16);
+ if (cchWidth < 0)
+ {
+ cchWidth = s_aTypes[i].cb * 2 + (fFlags & RTSTR_F_SPECIAL ? 2 : 0);
+ fFlags |= RTSTR_F_ZEROPAD;
+ }
+ cch = RTStrFormatNumber(szBuf, u.u64, s_aTypes[i].u8Base, cchWidth, cchPrecision, fFlags);
+ break;
+ }
+
+ case RTSF_BOOL:
+ {
+ static const char s_szTrue[] = "true ";
+ static const char s_szFalse[] = "false";
+ if (u.u64 == 1)
+ return pfnOutput(pvArgOutput, s_szTrue, sizeof(s_szTrue) - 1);
+ if (u.u64 == 0)
+ return pfnOutput(pvArgOutput, s_szFalse, sizeof(s_szFalse) - 1);
+ /* invalid boolean value */
+ return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "!%lld!", u.u64);
+ }
+
+ case RTSF_FP16:
+ {
+ fFlags &= ~(RTSTR_F_VALSIGNED | RTSTR_F_BIT_MASK | RTSTR_F_WIDTH | RTSTR_F_PRECISION | RTSTR_F_THOUSAND_SEP);
+ cch = RTStrFormatNumber(&szBuf[0], u.fp16.sel, 16, 4, -1, fFlags | RTSTR_F_16BIT);
+ Assert(cch == 4);
+ szBuf[4] = ':';
+ cch = RTStrFormatNumber(&szBuf[5], u.fp16.off, 16, 4, -1, fFlags | RTSTR_F_16BIT);
+ Assert(cch == 4);
+ cch = 4 + 1 + 4;
+ break;
+ }
+ case RTSF_FP32:
+ {
+ fFlags &= ~(RTSTR_F_VALSIGNED | RTSTR_F_BIT_MASK | RTSTR_F_WIDTH | RTSTR_F_PRECISION | RTSTR_F_THOUSAND_SEP);
+ cch = RTStrFormatNumber(&szBuf[0], u.fp32.sel, 16, 4, -1, fFlags | RTSTR_F_16BIT);
+ Assert(cch == 4);
+ szBuf[4] = ':';
+ cch = RTStrFormatNumber(&szBuf[5], u.fp32.off, 16, 8, -1, fFlags | RTSTR_F_32BIT);
+ Assert(cch == 8);
+ cch = 4 + 1 + 8;
+ break;
+ }
+ case RTSF_FP64:
+ {
+ fFlags &= ~(RTSTR_F_VALSIGNED | RTSTR_F_BIT_MASK | RTSTR_F_WIDTH | RTSTR_F_PRECISION | RTSTR_F_THOUSAND_SEP);
+ cch = RTStrFormatNumber(&szBuf[0], u.fp64.sel, 16, 4, -1, fFlags | RTSTR_F_16BIT);
+ Assert(cch == 4);
+ szBuf[4] = ':';
+ cch = RTStrFormatNumber(&szBuf[5], u.fp64.off, 16, 16, -1, fFlags | RTSTR_F_64BIT);
+ Assert(cch == 16);
+ cch = 4 + 1 + 16;
+ break;
+ }
+
+ case RTSF_IPV4:
+ return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
+ "%u.%u.%u.%u",
+ u.Ipv4Addr.au8[0],
+ u.Ipv4Addr.au8[1],
+ u.Ipv4Addr.au8[2],
+ u.Ipv4Addr.au8[3]);
+
+ case RTSF_IPV6:
+ {
+ if (VALID_PTR(u.pIpv6Addr))
+ return rtstrFormatIPv6(pfnOutput, pvArgOutput, u.pIpv6Addr);
+ return pfnOutput(pvArgOutput, s_szNull, sizeof(s_szNull) - 1);
+ }
+
+ case RTSF_MAC:
+ {
+ if (VALID_PTR(u.pMac))
+ return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
+ "%02x:%02x:%02x:%02x:%02x:%02x",
+ u.pMac->au8[0],
+ u.pMac->au8[1],
+ u.pMac->au8[2],
+ u.pMac->au8[3],
+ u.pMac->au8[4],
+ u.pMac->au8[5]);
+ return pfnOutput(pvArgOutput, s_szNull, sizeof(s_szNull) - 1);
+ }
+
+ case RTSF_NETADDR:
+ {
+ if (VALID_PTR(u.pNetAddr))
+ {
+ switch (u.pNetAddr->enmType)
+ {
+ case RTNETADDRTYPE_IPV4:
+ if (u.pNetAddr->uPort == RTNETADDR_PORT_NA)
+ return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
+ "%u.%u.%u.%u",
+ u.pNetAddr->uAddr.IPv4.au8[0],
+ u.pNetAddr->uAddr.IPv4.au8[1],
+ u.pNetAddr->uAddr.IPv4.au8[2],
+ u.pNetAddr->uAddr.IPv4.au8[3]);
+ return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
+ "%u.%u.%u.%u:%u",
+ u.pNetAddr->uAddr.IPv4.au8[0],
+ u.pNetAddr->uAddr.IPv4.au8[1],
+ u.pNetAddr->uAddr.IPv4.au8[2],
+ u.pNetAddr->uAddr.IPv4.au8[3],
+ u.pNetAddr->uPort);
+
+ case RTNETADDRTYPE_IPV6:
+ if (u.pNetAddr->uPort == RTNETADDR_PORT_NA)
+ return rtstrFormatIPv6(pfnOutput, pvArgOutput, &u.pNetAddr->uAddr.IPv6);
+
+ return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
+ "[%RTnaipv6]:%u",
+ &u.pNetAddr->uAddr.IPv6,
+ u.pNetAddr->uPort);
+
+ case RTNETADDRTYPE_MAC:
+ return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
+ "%02x:%02x:%02x:%02x:%02x:%02x",
+ u.pNetAddr->uAddr.Mac.au8[0],
+ u.pNetAddr->uAddr.Mac.au8[1],
+ u.pNetAddr->uAddr.Mac.au8[2],
+ u.pNetAddr->uAddr.Mac.au8[3],
+ u.pNetAddr->uAddr.Mac.au8[4],
+ u.pNetAddr->uAddr.Mac.au8[5]);
+
+ default:
+ return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
+ "unsupported-netaddr-type=%u", u.pNetAddr->enmType);
+
+ }
+ }
+ return pfnOutput(pvArgOutput, s_szNull, sizeof(s_szNull) - 1);
+ }
+
+ case RTSF_UUID:
+ {
+ if (VALID_PTR(u.pUuid))
+ {
+ /* cannot call RTUuidToStr because of GC/R0. */
+ return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
+ "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ RT_H2LE_U32(u.pUuid->Gen.u32TimeLow),
+ RT_H2LE_U16(u.pUuid->Gen.u16TimeMid),
+ RT_H2LE_U16(u.pUuid->Gen.u16TimeHiAndVersion),
+ u.pUuid->Gen.u8ClockSeqHiAndReserved,
+ u.pUuid->Gen.u8ClockSeqLow,
+ u.pUuid->Gen.au8Node[0],
+ u.pUuid->Gen.au8Node[1],
+ u.pUuid->Gen.au8Node[2],
+ u.pUuid->Gen.au8Node[3],
+ u.pUuid->Gen.au8Node[4],
+ u.pUuid->Gen.au8Node[5]);
+ }
+ return pfnOutput(pvArgOutput, s_szNull, sizeof(s_szNull) - 1);
+ }
+
+ default:
+ AssertMsgFailed(("Internal error %d\n", s_aTypes[i].enmFormat));
+ return 0;
+ }
+
+ /*
+ * Finally, output the formatted string and return.
+ */
+ return pfnOutput(pvArgOutput, szBuf, cch);
+ }
+
+
+ /* Group 3 */
+
+ /*
+ * Base name printing.
+ */
+ case 'b':
+ {
+ switch (*(*ppszFormat)++)
+ {
+ case 'n':
+ {
+ const char *pszLastSep;
+ const char *psz = pszLastSep = va_arg(*pArgs, const char *);
+ if (!VALID_PTR(psz))
+ return pfnOutput(pvArgOutput, RT_STR_TUPLE("<null>"));
+
+ while ((ch = *psz) != '\0')
+ {
+ if (RTPATH_IS_SEP(ch))
+ {
+ do
+ psz++;
+ while ((ch = *psz) != '\0' && RTPATH_IS_SEP(ch));
+ if (!ch)
+ break;
+ pszLastSep = psz;
+ }
+ psz++;
+ }
+
+ return pfnOutput(pvArgOutput, pszLastSep, psz - pszLastSep);
+ }
+
+ default:
+ AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
+ break;
+ }
+ break;
+ }
+
+
+ /*
+ * Pretty function / method name printing.
+ */
+ case 'f':
+ {
+ switch (*(*ppszFormat)++)
+ {
+ /*
+ * Pretty function / method name printing.
+ * This isn't 100% right (see classic signal prototype) and it assumes
+ * standardized names, but it'll do for today.
+ */
+ case 'n':
+ {
+ const char *pszStart;
+ const char *psz = pszStart = va_arg(*pArgs, const char *);
+ int cAngle = 0;
+
+ if (!VALID_PTR(psz))
+ return pfnOutput(pvArgOutput, RT_STR_TUPLE("<null>"));
+
+ while ((ch = *psz) != '\0' && ch != '(')
+ {
+ if (RT_C_IS_BLANK(ch))
+ {
+ psz++;
+ while ((ch = *psz) != '\0' && (RT_C_IS_BLANK(ch) || ch == '('))
+ psz++;
+ if (ch && cAngle == 0)
+ pszStart = psz;
+ }
+ else if (ch == '(')
+ break;
+ else if (ch == '<')
+ {
+ cAngle++;
+ psz++;
+ }
+ else if (ch == '>')
+ {
+ cAngle--;
+ psz++;
+ }
+ else
+ psz++;
+ }
+
+ return pfnOutput(pvArgOutput, pszStart, psz - pszStart);
+ }
+
+ default:
+ AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
+ break;
+ }
+ break;
+ }
+
+
+ /*
+ * hex dumping and COM/XPCOM.
+ */
+ case 'h':
+ {
+ switch (*(*ppszFormat)++)
+ {
+ /*
+ * Hex stuff.
+ */
+ case 'x':
+ {
+ uint8_t *pu8 = va_arg(*pArgs, uint8_t *);
+ if (cchPrecision < 0)
+ cchPrecision = 16;
+ if (pu8)
+ {
+ switch (*(*ppszFormat)++)
+ {
+ /*
+ * Regular hex dump.
+ */
+ case 'd':
+ {
+ int off = 0;
+ cch = 0;
+
+ if (cchWidth <= 0)
+ cchWidth = 16;
+
+ while (off < cchPrecision)
+ {
+ int i;
+ cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%s%0*p %04x:", off ? "\n" : "", sizeof(pu8) * 2, (uintptr_t)pu8, off);
+ for (i = 0; i < cchWidth && off + i < cchPrecision ; i++)
+ cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
+ off + i < cchPrecision ? !(i & 7) && i ? "-%02x" : " %02x" : " ", pu8[i]);
+ while (i++ < cchWidth)
+ cch += pfnOutput(pvArgOutput, " ", 3);
+
+ cch += pfnOutput(pvArgOutput, " ", 1);
+
+ for (i = 0; i < cchWidth && off + i < cchPrecision; i++)
+ {
+ uint8_t u8 = pu8[i];
+ cch += pfnOutput(pvArgOutput, u8 < 127 && u8 >= 32 ? (const char *)&u8 : ".", 1);
+ }
+
+ /* next */
+ pu8 += cchWidth;
+ off += cchWidth;
+ }
+ return cch;
+ }
+
+ /*
+ * Hex string.
+ */
+ case 's':
+ {
+ if (cchPrecision-- > 0)
+ {
+ cch = RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%02x", *pu8++);
+ for (; cchPrecision > 0; cchPrecision--, pu8++)
+ cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, " %02x", *pu8);
+ return cch;
+ }
+ break;
+ }
+
+ default:
+ AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
+ break;
+ }
+ }
+ else
+ return pfnOutput(pvArgOutput, RT_STR_TUPLE("<null>"));
+ break;
+ }
+
+
+#ifdef IN_RING3
+ /*
+ * XPCOM / COM status code: %Rhrc, %Rhrf, %Rhra
+ * ASSUMES: If Windows Then COM else XPCOM.
+ */
+ case 'r':
+ {
+ uint32_t hrc = va_arg(*pArgs, uint32_t);
+ PCRTCOMERRMSG pMsg = RTErrCOMGet(hrc);
+ switch (*(*ppszFormat)++)
+ {
+ case 'c':
+ return pfnOutput(pvArgOutput, pMsg->pszDefine, strlen(pMsg->pszDefine));
+ case 'f':
+ return pfnOutput(pvArgOutput, pMsg->pszMsgFull,strlen(pMsg->pszMsgFull));
+ case 'a':
+ return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%s (0x%08X) - %s", pMsg->pszDefine, hrc, pMsg->pszMsgFull);
+ default:
+ AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
+ return 0;
+ }
+ break;
+ }
+#endif /* IN_RING3 */
+
+ default:
+ AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
+ return 0;
+
+ }
+ break;
+ }
+
+ /*
+ * iprt status code: %Rrc, %Rrs, %Rrf, %Rra.
+ */
+ case 'r':
+ {
+ int rc = va_arg(*pArgs, int);
+#ifdef IN_RING3 /* we don't want this anywhere else yet. */
+ PCRTSTATUSMSG pMsg = RTErrGet(rc);
+ switch (*(*ppszFormat)++)
+ {
+ case 'c':
+ return pfnOutput(pvArgOutput, pMsg->pszDefine, strlen(pMsg->pszDefine));
+ case 's':
+ return pfnOutput(pvArgOutput, pMsg->pszMsgShort, strlen(pMsg->pszMsgShort));
+ case 'f':
+ return pfnOutput(pvArgOutput, pMsg->pszMsgFull, strlen(pMsg->pszMsgFull));
+ case 'a':
+ return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%s (%d) - %s", pMsg->pszDefine, rc, pMsg->pszMsgFull);
+ default:
+ AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
+ return 0;
+ }
+#else /* !IN_RING3 */
+ switch (*(*ppszFormat)++)
+ {
+ case 'c':
+ case 's':
+ case 'f':
+ case 'a':
+ return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%d", rc);
+ default:
+ AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
+ return 0;
+ }
+#endif /* !IN_RING3 */
+ break;
+ }
+
+#if defined(IN_RING3)
+ /*
+ * Windows status code: %Rwc, %Rwf, %Rwa
+ */
+ case 'w':
+ {
+ long rc = va_arg(*pArgs, long);
+# if defined(RT_OS_WINDOWS)
+ PCRTWINERRMSG pMsg = RTErrWinGet(rc);
+# endif
+ switch (*(*ppszFormat)++)
+ {
+# if defined(RT_OS_WINDOWS)
+ case 'c':
+ return pfnOutput(pvArgOutput, pMsg->pszDefine, strlen(pMsg->pszDefine));
+ case 'f':
+ return pfnOutput(pvArgOutput, pMsg->pszMsgFull,strlen(pMsg->pszMsgFull));
+ case 'a':
+ return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%s (0x%08X) - %s", pMsg->pszDefine, rc, pMsg->pszMsgFull);
+# else
+ case 'c':
+ case 'f':
+ case 'a':
+ return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "0x%08X", rc);
+# endif
+ default:
+ AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
+ return 0;
+ }
+ break;
+ }
+#endif /* IN_RING3 */
+
+ /*
+ * Group 4, structure dumpers.
+ */
+ case 'D':
+ {
+ /*
+ * Interpret the type.
+ */
+ typedef enum
+ {
+ RTST_TIMESPEC
+ } RTST;
+/** Set if it's a pointer */
+#define RTST_FLAGS_POINTER RT_BIT(0)
+ static const struct
+ {
+ uint8_t cch; /**< the length of the string. */
+ char sz[16-2]; /**< the part following 'R'. */
+ uint8_t cb; /**< the size of the argument. */
+ uint8_t fFlags; /**< RTST_FLAGS_* */
+ RTST enmType; /**< The structure type. */
+ }
+ /** Sorted array of types, looked up using binary search! */
+ s_aTypes[] =
+ {
+#define STRMEM(str) sizeof(str) - 1, str
+ { STRMEM("Dtimespec"), sizeof(PCRTTIMESPEC), RTST_FLAGS_POINTER, RTST_TIMESPEC},
+#undef STRMEM
+ };
+ const char *pszType = *ppszFormat - 1;
+ int iStart = 0;
+ int iEnd = RT_ELEMENTS(s_aTypes) - 1;
+ int i = RT_ELEMENTS(s_aTypes) / 2;
+
+ union
+ {
+ const void *pv;
+ uint64_t u64;
+ PCRTTIMESPEC pTimeSpec;
+ } u;
+
+ AssertMsg(!chArgSize, ("Not argument size '%c' for RT types! '%.10s'\n", chArgSize, pszFormatOrg));
+
+ /*
+ * Lookup the type - binary search.
+ */
+ for (;;)
+ {
+ int iDiff = strncmp(pszType, s_aTypes[i].sz, s_aTypes[i].cch);
+ if (!iDiff)
+ break;
+ if (iEnd == iStart)
+ {
+ AssertMsgFailed(("Invalid format type '%.10s'!\n", pszFormatOrg));
+ return 0;
+ }
+ if (iDiff < 0)
+ iEnd = i - 1;
+ else
+ iStart = i + 1;
+ if (iEnd < iStart)
+ {
+ AssertMsgFailed(("Invalid format type '%.10s'!\n", pszFormatOrg));
+ return 0;
+ }
+ i = iStart + (iEnd - iStart) / 2;
+ }
+ *ppszFormat += s_aTypes[i].cch - 1;
+
+ /*
+ * Fetch the argument.
+ */
+ u.u64 = 0;
+ switch (s_aTypes[i].cb)
+ {
+ case sizeof(const void *):
+ u.pv = va_arg(*pArgs, const void *);
+ break;
+ default:
+ AssertMsgFailed(("Invalid format error, size %d'!\n", s_aTypes[i].cb));
+ break;
+ }
+
+ /*
+ * If it's a pointer, we'll check if it's valid before going on.
+ */
+ if ((s_aTypes[i].fFlags & RTST_FLAGS_POINTER) && !VALID_PTR(u.pv))
+ return pfnOutput(pvArgOutput, RT_STR_TUPLE("<null>"));
+
+ /*
+ * Format the output.
+ */
+ switch (s_aTypes[i].enmType)
+ {
+ case RTST_TIMESPEC:
+ return RTStrFormat(pfnOutput, pvArgOutput, NULL, NULL, "%'lld ns", RTTimeSpecGetNano(u.pTimeSpec));
+
+ default:
+ AssertMsgFailed(("Invalid/unhandled enmType=%d\n", s_aTypes[i].enmType));
+ break;
+ }
+ break;
+ }
+
+#ifdef IN_RING3
+ /*
+ * Group 5, XML / HTML escapers.
+ */
+ case 'M':
+ {
+ char chWhat = (*ppszFormat)[0];
+ bool fAttr = chWhat == 'a';
+ char chType = (*ppszFormat)[1];
+ AssertMsgBreak(chWhat == 'a' || chWhat == 'e', ("Invalid IPRT format type '%.10s'!\n", pszFormatOrg));
+ *ppszFormat += 2;
+ switch (chType)
+ {
+ case 's':
+ {
+ static const char s_szElemEscape[] = "<>&\"'";
+ static const char s_szAttrEscape[] = "<>&\"\n\r"; /* more? */
+ const char * const pszEscape = fAttr ? s_szAttrEscape : s_szElemEscape;
+ size_t const cchEscape = (fAttr ? RT_ELEMENTS(s_szAttrEscape) : RT_ELEMENTS(s_szElemEscape)) - 1;
+ size_t cchOutput = 0;
+ const char *pszStr = va_arg(*pArgs, char *);
+ ssize_t cchStr;
+ ssize_t offCur;
+ ssize_t offLast;
+
+ if (!VALID_PTR(pszStr))
+ pszStr = "<NULL>";
+ cchStr = RTStrNLen(pszStr, (unsigned)cchPrecision);
+
+ if (fAttr)
+ cchOutput += pfnOutput(pvArgOutput, "\"", 1);
+ if (!(fFlags & RTSTR_F_LEFT))
+ while (--cchWidth >= cchStr)
+ cchOutput += pfnOutput(pvArgOutput, " ", 1);
+
+ offLast = offCur = 0;
+ while (offCur < cchStr)
+ {
+ if (memchr(pszEscape, pszStr[offCur], cchEscape))
+ {
+ if (offLast < offCur)
+ cchOutput += pfnOutput(pvArgOutput, &pszStr[offLast], offCur - offLast);
+ switch (pszStr[offCur])
+ {
+ case '<': cchOutput += pfnOutput(pvArgOutput, "<", 4); break;
+ case '>': cchOutput += pfnOutput(pvArgOutput, ">", 4); break;
+ case '&': cchOutput += pfnOutput(pvArgOutput, "&", 5); break;
+ case '\'': cchOutput += pfnOutput(pvArgOutput, "'", 6); break;
+ case '"': cchOutput += pfnOutput(pvArgOutput, """, 6); break;
+ case '\n': cchOutput += pfnOutput(pvArgOutput, "
", 5); break;
+ case '\r': cchOutput += pfnOutput(pvArgOutput, "
", 5); break;
+ default:
+ AssertFailed();
+ }
+ offLast = offCur + 1;
+ }
+ offCur++;
+ }
+ if (offLast < offCur)
+ cchOutput += pfnOutput(pvArgOutput, &pszStr[offLast], offCur - offLast);
+
+ while (--cchWidth >= cchStr)
+ cchOutput += pfnOutput(pvArgOutput, " ", 1);
+ if (fAttr)
+ cchOutput += pfnOutput(pvArgOutput, "\"", 1);
+ return cchOutput;
+ }
+
+ default:
+ AssertMsgFailed(("Invalid IPRT format type '%.10s'!\n", pszFormatOrg));
+ }
+ break;
+ }
+#endif /* IN_RING3 */
+
+
+ /*
+ * Groups 6 - CPU Architecture Register Formatters.
+ * "%RAarch[reg]"
+ */
+ case 'A':
+ {
+ char const * const pszArch = *ppszFormat;
+ const char *pszReg = pszArch;
+ size_t cchOutput = 0;
+ int cPrinted = 0;
+ size_t cchReg;
+
+ /* Parse out the */
+ while ((ch = *pszReg++) && ch != '[')
+ { /* nothing */ }
+ AssertMsgBreak(ch == '[', ("Malformed IPRT architecture register format type '%.10s'!\n", pszFormatOrg));
+
+ cchReg = 0;
+ while ((ch = pszReg[cchReg]) && ch != ']')
+ cchReg++;
+ AssertMsgBreak(ch == ']', ("Malformed IPRT architecture register format type '%.10s'!\n", pszFormatOrg));
+
+ *ppszFormat = &pszReg[cchReg + 1];
+
+
+#define REG_EQUALS(a_szReg) (sizeof(a_szReg) - 1 == cchReg && !strncmp(a_szReg, pszReg, sizeof(a_szReg) - 1))
+#define REG_OUT_BIT(a_uVal, a_fBitMask, a_szName) \
+ do { \
+ if ((a_uVal) & (a_fBitMask)) \
+ { \
+ if (!cPrinted++) \
+ cchOutput += pfnOutput(pvArgOutput, "{" a_szName, sizeof(a_szName)); \
+ else \
+ cchOutput += pfnOutput(pvArgOutput, "," a_szName, sizeof(a_szName)); \
+ (a_uVal) &= ~(a_fBitMask); \
+ } \
+ } while (0)
+#define REG_OUT_CLOSE(a_uVal) \
+ do { \
+ if ((a_uVal)) \
+ { \
+ cchOutput += pfnOutput(pvArgOutput, !cPrinted ? "{unkn=" : ",unkn=", 6); \
+ cch = RTStrFormatNumber(&szBuf[0], (a_uVal), 16, 1, -1, fFlags); \
+ cchOutput += pfnOutput(pvArgOutput, szBuf, cch); \
+ cPrinted++; \
+ } \
+ if (cPrinted) \
+ cchOutput += pfnOutput(pvArgOutput, "}", 1); \
+ } while (0)
+
+
+ if (0)
+ { /* dummy */ }
+#ifdef STRFORMAT_WITH_X86
+ /*
+ * X86 & AMD64.
+ */
+ else if ( pszReg - pszArch == 3 + 1
+ && pszArch[0] == 'x'
+ && pszArch[1] == '8'
+ && pszArch[2] == '6')
+ {
+ if (REG_EQUALS("cr0"))
+ {
+ uint64_t cr0 = va_arg(*pArgs, uint64_t);
+ fFlags |= RTSTR_F_64BIT;
+ cch = RTStrFormatNumber(&szBuf[0], cr0, 16, 8, -1, fFlags | RTSTR_F_ZEROPAD);
+ cchOutput += pfnOutput(pvArgOutput, szBuf, cch);
+ REG_OUT_BIT(cr0, X86_CR0_PE, "PE");
+ REG_OUT_BIT(cr0, X86_CR0_MP, "MP");
+ REG_OUT_BIT(cr0, X86_CR0_EM, "EM");
+ REG_OUT_BIT(cr0, X86_CR0_TS, "DE");
+ REG_OUT_BIT(cr0, X86_CR0_ET, "ET");
+ REG_OUT_BIT(cr0, X86_CR0_NE, "NE");
+ REG_OUT_BIT(cr0, X86_CR0_WP, "WP");
+ REG_OUT_BIT(cr0, X86_CR0_AM, "AM");
+ REG_OUT_BIT(cr0, X86_CR0_NW, "NW");
+ REG_OUT_BIT(cr0, X86_CR0_CD, "CD");
+ REG_OUT_BIT(cr0, X86_CR0_PG, "PG");
+ REG_OUT_CLOSE(cr0);
+ }
+ else if (REG_EQUALS("cr4"))
+ {
+ uint64_t cr4 = va_arg(*pArgs, uint64_t);
+ fFlags |= RTSTR_F_64BIT;
+ cch = RTStrFormatNumber(&szBuf[0], cr4, 16, 8, -1, fFlags | RTSTR_F_ZEROPAD);
+ cchOutput += pfnOutput(pvArgOutput, szBuf, cch);
+ REG_OUT_BIT(cr4, X86_CR4_VME, "VME");
+ REG_OUT_BIT(cr4, X86_CR4_PVI, "PVI");
+ REG_OUT_BIT(cr4, X86_CR4_TSD, "TSD");
+ REG_OUT_BIT(cr4, X86_CR4_DE, "DE");
+ REG_OUT_BIT(cr4, X86_CR4_PSE, "PSE");
+ REG_OUT_BIT(cr4, X86_CR4_PAE, "PAE");
+ REG_OUT_BIT(cr4, X86_CR4_MCE, "MCE");
+ REG_OUT_BIT(cr4, X86_CR4_PGE, "PGE");
+ REG_OUT_BIT(cr4, X86_CR4_PCE, "PCE");
+ REG_OUT_BIT(cr4, X86_CR4_OSFXSR, "OSFXSR");
+ REG_OUT_BIT(cr4, X86_CR4_OSXMMEEXCPT, "OSXMMEEXCPT");
+ REG_OUT_BIT(cr4, X86_CR4_VMXE, "VMXE");
+ REG_OUT_BIT(cr4, X86_CR4_SMXE, "SMXE");
+ REG_OUT_BIT(cr4, X86_CR4_PCIDE, "PCIDE");
+ REG_OUT_BIT(cr4, X86_CR4_OSXSAVE, "OSXSAVE");
+ REG_OUT_BIT(cr4, X86_CR4_SMEP, "SMEP");
+ REG_OUT_BIT(cr4, X86_CR4_SMAP, "SMAP");
+ REG_OUT_CLOSE(cr4);
+ }
+ else
+ AssertMsgFailed(("Unknown x86 register specified in '%.10s'!\n", pszFormatOrg));
+ }
+#endif
+ else
+ AssertMsgFailed(("Unknown architecture specified in '%.10s'!\n", pszFormatOrg));
+#undef REG_OUT_BIT
+#undef REG_OUT_CLOSE
+#undef REG_EQUALS
+ return cchOutput;
+ }
+
+ /*
+ * Invalid/Unknown. Bitch about it.
+ */
+ default:
+ AssertMsgFailed(("Invalid IPRT format type '%.10s'!\n", pszFormatOrg));
+ break;
+ }
+ }
+ else
+ AssertMsgFailed(("Invalid IPRT format type '%.10s'!\n", pszFormatOrg));
+
+ NOREF(pszFormatOrg);
+ return 0;
+}
+
--- /dev/null
+/* $Id: strformattype.cpp $ */
+/** @file
+ * IPRT - IPRT String Formatter Extensions, Dynamic Types.
+ */
+
+/*
+ * Copyright (C) 2008-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+#define LOG_GROUP RTLOGGROUP_STRING
+#include <iprt/string.h>
+#include "internal/iprt.h"
+
+#include <iprt/assert.h>
+#include <iprt/stdarg.h>
+#include <iprt/asm.h>
+#include "internal/string.h"
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+#ifdef RT_STRICT
+# define RTSTRFORMATTYPE_WITH_LOCKING
+#endif
+#ifdef RTSTRFORMATTYPE_WITH_LOCKING
+# define RTSTRFORMATTYPE_LOCK_OFFSET 0x7fff0000
+#endif
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * Description of a registered formatting type.
+ *
+ * In GC we'll be using offsets instead of pointers just to try avoid having to
+ * do the bothersome relocating. This of course assumes that all the relevant
+ * code stays within the same mapping.
+ */
+typedef struct RTSTRDYNFMT
+{
+ /** The length of the type. */
+ uint8_t cchType;
+ /** The type name. */
+ char szType[47];
+ /** The handler function.
+ * In GC the offset is relative to g_aTypes[0], so that &g_aTypes[0] + offHandler
+ * gives the actual address. */
+#ifdef IN_RC
+ int32_t offHandler;
+#else
+ PFNRTSTRFORMATTYPE pfnHandler;
+#endif
+ /** Callback argument. */
+ void * volatile pvUser;
+#if ARCH_BITS == 32
+ /** Size alignment padding. */
+ char abPadding[8];
+#endif
+} RTSTRDYNFMT;
+AssertCompileSizeAlignment(RTSTRDYNFMT, 32);
+typedef RTSTRDYNFMT *PRTSTRDYNFMT;
+typedef RTSTRDYNFMT const *PCRTSTRDYNFMT;
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/** The registered types, sorted for binary lookup.
+ * We use a static array here because it avoids RTMemAlloc dependencies+leaks. */
+static RTSTRDYNFMT g_aTypes[64];
+/** The number of registered types. */
+static uint32_t g_cTypes = 0;
+#ifdef RTSTRFORMATTYPE_WITH_LOCKING
+/** This is just a thing we assert/spin on.
+ * Zero == unlocked, negative == write locked, positive == read locked.
+ *
+ * The user should do all the serialization and we'll smack his fingers in
+ * strict builds if he doesn't. */
+static int32_t volatile g_i32Spinlock = 0;
+#endif
+
+
+/**
+ * Locks the stuff for updating.
+ *
+ * Mostly for check that the caller is doing his job.
+ */
+DECLINLINE(void) rtstrFormatTypeWriteLock(void)
+{
+#if defined(RTSTRFORMATTYPE_WITH_LOCKING)
+ if (RT_UNLIKELY(!ASMAtomicCmpXchgS32(&g_i32Spinlock, -RTSTRFORMATTYPE_LOCK_OFFSET, 0)))
+ {
+ unsigned volatile i;
+
+ AssertFailed();
+ for (i = 0;; i++)
+ if ( !g_i32Spinlock
+ && ASMAtomicCmpXchgS32(&g_i32Spinlock, -RTSTRFORMATTYPE_LOCK_OFFSET, 0))
+ break;
+ }
+#endif
+}
+
+
+/**
+ * Undoing rtstrFormatTypeWriteLock.
+ */
+DECLINLINE(void) rtstrFormatTypeWriteUnlock(void)
+{
+#if defined(RTSTRFORMATTYPE_WITH_LOCKING)
+ Assert(g_i32Spinlock < 0);
+ ASMAtomicAddS32(&g_i32Spinlock, RTSTRFORMATTYPE_LOCK_OFFSET);
+#endif
+}
+
+
+/**
+ * Locks the stuff for reading.
+ *
+ * This is just cheap stuff to make sure the caller is doing the right thing.
+ */
+DECLINLINE(void) rtstrFormatTypeReadLock(void)
+{
+#if defined(RTSTRFORMATTYPE_WITH_LOCKING)
+ if (RT_UNLIKELY(ASMAtomicIncS32(&g_i32Spinlock) < 0))
+ {
+ unsigned volatile i;
+
+ AssertFailed();
+ for (i = 0;; i++)
+ if (ASMAtomicUoReadS32(&g_i32Spinlock) > 0)
+ break;
+ }
+#endif
+}
+
+
+/**
+ * Undoing rtstrFormatTypeReadLock.
+ */
+DECLINLINE(void) rtstrFormatTypeReadUnlock(void)
+{
+#if defined(RTSTRFORMATTYPE_WITH_LOCKING)
+ Assert(g_i32Spinlock > 0);
+ ASMAtomicDecS32(&g_i32Spinlock);
+#endif
+}
+
+
+/**
+ * Compares a type string with a type entry, the string doesn't need to be terminated.
+ *
+ * @returns Same as memcmp.
+ * @param pszType The type string, doesn't need to be terminated.
+ * @param cchType The number of chars in @a pszType to compare.
+ * @param pType The type entry to compare with.
+ */
+DECLINLINE(int) rtstrFormatTypeCompare(const char *pszType, size_t cchType, PCRTSTRDYNFMT pType)
+{
+ size_t cch = RT_MIN(cchType, pType->cchType);
+ int iDiff = memcmp(pszType, pType->szType, cch);
+ if (!iDiff)
+ {
+ if (cchType == pType->cchType)
+ return 0;
+ iDiff = cchType < pType->cchType ? -1 : 1;
+ }
+ return iDiff;
+}
+
+
+/**
+ * Looks up a type entry.
+ *
+ * @returns The type index, -1 on failure.
+ * @param pszType The type to look up. This doesn't have to be terminated.
+ * @param cchType The length of the type.
+ */
+DECLINLINE(int32_t) rtstrFormatTypeLookup(const char *pszType, size_t cchType)
+{
+ /*
+ * Lookup the type - binary search.
+ */
+ int32_t iStart = 0;
+ int32_t iEnd = g_cTypes - 1;
+ int32_t i = iEnd / 2;
+ for (;;)
+ {
+ int iDiff = rtstrFormatTypeCompare(pszType, cchType, &g_aTypes[i]);
+ if (!iDiff)
+ return i;
+ if (iEnd == iStart)
+ break;
+ if (iDiff < 0)
+ iEnd = i - 1;
+ else
+ iStart = i + 1;
+ if (iEnd < iStart)
+ break;
+ i = iStart + (iEnd - iStart) / 2;
+ }
+ return -1;
+}
+
+
+/**
+ * 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)
+{
+ int rc;
+ size_t cchType;
+ uint32_t cTypes;
+
+ /*
+ * Validate input.
+ */
+ AssertPtr(pfnHandler);
+ AssertPtr(pszType);
+ cchType = strlen(pszType);
+ AssertReturn(cchType < RT_SIZEOFMEMB(RTSTRDYNFMT, szType), VERR_INVALID_PARAMETER);
+
+ /*
+ * Try add it.
+ */
+ rtstrFormatTypeWriteLock();
+
+ /* check that there are empty slots. */
+ cTypes = g_cTypes;
+ if (cTypes < RT_ELEMENTS(g_aTypes))
+ {
+ /* find where to insert it. */
+ uint32_t i = 0;
+ rc = VINF_SUCCESS;
+ while (i < cTypes)
+ {
+ int iDiff = rtstrFormatTypeCompare(pszType, cchType, &g_aTypes[i]);
+ if (!iDiff)
+ {
+ rc = VERR_ALREADY_EXISTS;
+ break;
+ }
+ if (iDiff < 0)
+ break;
+ i++;
+ }
+ if (RT_SUCCESS(rc))
+ {
+ /* make room. */
+ uint32_t cToMove = cTypes - i;
+ if (cToMove)
+ memmove(&g_aTypes[i + 1], &g_aTypes[i], cToMove * sizeof(g_aTypes[i]));
+
+ /* insert the new entry. */
+ memset(&g_aTypes[i], 0, sizeof(g_aTypes[i]));
+ memcpy(&g_aTypes[i].szType[0], pszType, cchType + 1);
+ g_aTypes[i].cchType = (uint8_t)cchType;
+ g_aTypes[i].pvUser = pvUser;
+#ifdef IN_RC
+ g_aTypes[i].offHandler = (intptr_t)pfnHandler - (intptr_t)&g_aTypes[0];
+#else
+ g_aTypes[i].pfnHandler = pfnHandler;
+#endif
+ ASMAtomicIncU32(&g_cTypes);
+ rc = VINF_SUCCESS;
+ }
+ }
+ else
+ rc = VERR_TOO_MANY_OPEN_FILES; /** @todo fix error code */
+
+ rtstrFormatTypeWriteUnlock();
+
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTStrFormatTypeRegister);
+
+
+/**
+ * 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)
+{
+ int32_t i;
+
+ /*
+ * Validate input.
+ */
+ AssertPtr(pszType);
+
+ /*
+ * Locate the entry and remove it.
+ */
+ rtstrFormatTypeWriteLock();
+ i = rtstrFormatTypeLookup(pszType, strlen(pszType));
+ if (i >= 0)
+ {
+ const uint32_t cTypes = g_cTypes;
+ int32_t cToMove = cTypes - i - 1;
+ if (cToMove > 0)
+ memmove(&g_aTypes[i], &g_aTypes[i + 1], cToMove * sizeof(g_aTypes[i]));
+ memset(&g_aTypes[cTypes - 1], 0, sizeof(g_aTypes[0]));
+ ASMAtomicDecU32(&g_cTypes);
+ }
+ rtstrFormatTypeWriteUnlock();
+
+ Assert(i >= 0);
+ return i >= 0
+ ? VINF_SUCCESS
+ : VERR_FILE_NOT_FOUND; /** @todo fix status code */
+}
+RT_EXPORT_SYMBOL(RTStrFormatTypeDeregister);
+
+
+/**
+ * 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)
+{
+ int32_t i;
+
+ /*
+ * Validate input.
+ */
+ AssertPtr(pszType);
+
+ /*
+ * Locate the entry and update it.
+ */
+ rtstrFormatTypeReadLock();
+
+ i = rtstrFormatTypeLookup(pszType, strlen(pszType));
+ if (i >= 0)
+ ASMAtomicWritePtr(&g_aTypes[i].pvUser, pvUser);
+
+ rtstrFormatTypeReadUnlock();
+
+ Assert(i >= 0);
+ return i >= 0
+ ? VINF_SUCCESS
+ : VERR_FILE_NOT_FOUND; /** @todo fix status code */
+}
+RT_EXPORT_SYMBOL(RTStrFormatTypeSetUser);
+
+
+/**
+ * Formats a type using a registered callback handler.
+ *
+ * This will handle %R[type].
+ *
+ * @returns The number of bytes formatted.
+ * @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'.
+ */
+DECLHIDDEN(size_t) rtstrFormatType(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, const char **ppszFormat,
+ va_list *pArgs, int cchWidth, int cchPrecision, unsigned fFlags, char chArgSize)
+{
+ size_t cch;
+ int32_t i;
+ char const *pszTypeEnd;
+ char const *pszType;
+ char ch;
+ void *pvValue = va_arg(*pArgs, void *);
+ NOREF(chArgSize);
+
+ /*
+ * Parse out the type.
+ */
+ pszType = *ppszFormat + 2;
+ *ppszFormat = pszType;
+ Assert(pszType[-1] == '[');
+ Assert(pszType[-2] == 'R');
+ pszTypeEnd = pszType;
+ while ((ch = *pszTypeEnd) != ']')
+ {
+ AssertReturn(ch != '\0', 0);
+ AssertReturn(ch != '%', 0);
+ AssertReturn(ch != '[', 0);
+ pszTypeEnd++;
+ }
+ *ppszFormat = pszTypeEnd + 1;
+
+ /*
+ * Locate the entry and call the handler.
+ */
+ rtstrFormatTypeReadLock();
+
+ i = rtstrFormatTypeLookup(pszType, pszTypeEnd - pszType);
+ if (RT_LIKELY(i >= 0))
+ {
+#ifdef IN_RC
+ PFNRTSTRFORMATTYPE pfnHandler = (PFNRTSTRFORMATTYPE)((intptr_t)&g_aTypes[0] + g_aTypes[i].offHandler);
+#else
+ PFNRTSTRFORMATTYPE pfnHandler = g_aTypes[i].pfnHandler;
+#endif
+ void *pvUser = ASMAtomicReadPtr(&g_aTypes[i].pvUser);
+
+ rtstrFormatTypeReadUnlock();
+
+ cch = pfnHandler(pfnOutput, pvArgOutput, g_aTypes[i].szType, pvValue, cchWidth, cchPrecision, fFlags, pvUser);
+ }
+ else
+ {
+ rtstrFormatTypeReadUnlock();
+
+ cch = pfnOutput(pvArgOutput, RT_STR_TUPLE("<missing:%R["));
+ cch += pfnOutput(pvArgOutput, pszType, pszTypeEnd - pszType);
+ cch += pfnOutput(pvArgOutput, RT_STR_TUPLE("]>"));
+ }
+
+ return cch;
+}
+
--- /dev/null
+/* $Id: strprintf.cpp $ */
+/** @file
+ * IPRT - String Formatters.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/string.h>
+#include "internal/iprt.h"
+
+#include <iprt/assert.h>
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/** strbufoutput() argument structure. */
+typedef struct STRBUFARG
+{
+ /** Pointer to current buffer position. */
+ char *psz;
+ /** Number of bytes left in the buffer - not including the trailing zero. */
+ size_t cch;
+} STRBUFARG;
+/** Pointer to a strbufoutput() argument structure. */
+typedef STRBUFARG *PSTRBUFARG;
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+static DECLCALLBACK(size_t) strbufoutput(void *pvArg, const char *pachChars, size_t cbChars);
+
+
+/**
+ * Output callback.
+ *
+ * @returns number of bytes written.
+ * @param pvArg Pointer to a STRBUFARG structure.
+ * @param pachChars Pointer to an array of utf-8 characters.
+ * @param cbChars Number of bytes in the character array pointed to by pachChars.
+ */
+static DECLCALLBACK(size_t) strbufoutput(void *pvArg, const char *pachChars, size_t cbChars)
+{
+ PSTRBUFARG pArg = (PSTRBUFARG)pvArg;
+ char *pszCur = pArg->psz; /* We actually have to spell this out for VS2010, or it will load for each case. */
+
+ cbChars = RT_MIN(pArg->cch, cbChars);
+ if (cbChars)
+ {
+ pArg->cch -= cbChars;
+
+ /* Note! For VS2010/64 we need at least 7 case statements before it generates a jump table. */
+ switch (cbChars)
+ {
+ default:
+ memcpy(pszCur, pachChars, cbChars);
+ break;
+ case 8: pszCur[7] = pachChars[7]; /* fall thru */
+ case 7: pszCur[6] = pachChars[6]; /* fall thru */
+ case 6: pszCur[5] = pachChars[5]; /* fall thru */
+ case 5: pszCur[4] = pachChars[4]; /* fall thru */
+ case 4: pszCur[3] = pachChars[3]; /* fall thru */
+ case 3: pszCur[2] = pachChars[2]; /* fall thru */
+ case 2: pszCur[1] = pachChars[1]; /* fall thru */
+ case 1: pszCur[0] = pachChars[0]; /* fall thru */
+ case 0:
+ break;
+ }
+ pArg->psz = pszCur += cbChars;
+ }
+ *pszCur = '\0';
+
+ return cbChars;
+}
+
+
+RTDECL(size_t) RTStrPrintf(char *pszBuffer, size_t cchBuffer, const char *pszFormat, ...)
+{
+ /* Explicitly inline RTStrPrintfV + RTStrPrintfExV here because this is a frequently use API. */
+ STRBUFARG Arg;
+ va_list args;
+ size_t cbRet;
+
+ AssertMsgReturn(cchBuffer, ("Excellent idea! Format a string with no space for the output!\n"), 0);
+ Arg.psz = pszBuffer;
+ Arg.cch = cchBuffer - 1;
+
+ va_start(args, pszFormat);
+ cbRet = RTStrFormatV(strbufoutput, &Arg, NULL, NULL, pszFormat, args);
+ va_end(args);
+
+ return cbRet;
+}
+RT_EXPORT_SYMBOL(RTStrPrintf);
+
+
+RTDECL(size_t) RTStrPrintfExV(PFNSTRFORMAT pfnFormat, void *pvArg, char *pszBuffer, size_t cchBuffer, const char *pszFormat, va_list args)
+{
+ STRBUFARG Arg;
+ AssertMsgReturn(cchBuffer, ("Excellent idea! Format a string with no space for the output!\n"), 0);
+ Arg.psz = pszBuffer;
+ Arg.cch = cchBuffer - 1;
+ return RTStrFormatV(strbufoutput, &Arg, pfnFormat, pvArg, pszFormat, args);
+}
+RT_EXPORT_SYMBOL(RTStrPrintfExV);
+
+
+RTDECL(size_t) RTStrPrintfV(char *pszBuffer, size_t cchBuffer, const char *pszFormat, va_list args)
+{
+ return RTStrPrintfExV(NULL, NULL, pszBuffer, cchBuffer, pszFormat, args);
+}
+RT_EXPORT_SYMBOL(RTStrPrintfV);
+
+
+RTDECL(size_t) RTStrPrintfEx(PFNSTRFORMAT pfnFormat, void *pvArg, char *pszBuffer, size_t cchBuffer, const char *pszFormat, ...)
+{
+ va_list args;
+ size_t cbRet;
+ va_start(args, pszFormat);
+ cbRet = RTStrPrintfExV(pfnFormat, pvArg, pszBuffer, cchBuffer, pszFormat, args);
+ va_end(args);
+ return cbRet;
+}
+RT_EXPORT_SYMBOL(RTStrPrintfEx);
+
--- /dev/null
+/* $Id: strtonum.cpp $ */
+/** @file
+ * IPRT - String To Number Conversion.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/string.h>
+#include "internal/iprt.h"
+
+#include <iprt/assert.h>
+#include <iprt/ctype.h> /* needed for RT_C_IS_DIGIT */
+#include <iprt/err.h>
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/** 8-bit char -> digit. */
+static const unsigned char g_auchDigits[256] =
+{
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,255,255,255,255,255,255,
+ 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,255,255,255,255,255,
+ 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
+};
+/** Approximated overflow shift checks. */
+static const char g_auchShift[36] =
+{
+ /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 */
+ 64, 64, 63, 63, 62, 62, 62, 62, 61, 61, 61, 61, 61, 61, 61, 61, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 59, 59, 59, 59
+};
+
+/*
+#include <stdio.h>
+int main()
+{
+ int i;
+ printf("static const unsigned char g_auchDigits[256] =\n"
+ "{");
+ for (i = 0; i < 256; i++)
+ {
+ int ch = 255;
+ if (i >= '0' && i <= '9')
+ ch = i - '0';
+ else if (i >= 'a' && i <= 'z')
+ ch = i - 'a' + 10;
+ else if (i >= 'A' && i <= 'Z')
+ ch = i - 'A' + 10;
+ if (i == 0)
+ printf("\n %3d", ch);
+ else if ((i % 32) == 0)
+ printf(",\n %3d", ch);
+ else
+ printf(",%3d", ch);
+ }
+ printf("\n"
+ "};\n");
+ return 0;
+}
+*/
+
+
+/**
+ * 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 uBase The base of the representation used.
+ * If the function will look for known prefixes before defaulting to 10.
+ * @param pu64 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToUInt64Ex(const char *pszValue, char **ppszNext, unsigned uBase, uint64_t *pu64)
+{
+ const char *psz = pszValue;
+ int iShift;
+ int rc;
+ uint64_t u64;
+ unsigned char uch;
+
+ /*
+ * Positive/Negative stuff.
+ */
+ bool fPositive = true;
+ for (;; psz++)
+ {
+ if (*psz == '+')
+ fPositive = true;
+ else if (*psz == '-')
+ fPositive = !fPositive;
+ else
+ break;
+ }
+
+ /*
+ * Check for hex prefix.
+ */
+ if (!uBase)
+ {
+ if ( psz[0] == '0'
+ && (psz[1] == 'x' || psz[1] == 'X')
+ && g_auchDigits[(unsigned char)psz[2]] < 16)
+ {
+ uBase = 16;
+ psz += 2;
+ }
+ else if ( psz[0] == '0'
+ && g_auchDigits[(unsigned char)psz[1]] < 8)
+ {
+ uBase = 8;
+ psz++;
+ }
+ else
+ uBase = 10;
+ }
+ else if ( uBase == 16
+ && psz[0] == '0'
+ && (psz[1] == 'x' || psz[1] == 'X')
+ && g_auchDigits[(unsigned char)psz[2]] < 16)
+ psz += 2;
+
+ /*
+ * Interpret the value.
+ * Note: We only support ascii digits at this time... :-)
+ */
+ iShift = g_auchShift[uBase];
+ pszValue = psz; /* (Prefix and sign doesn't count in the digit counting.) */
+ rc = VINF_SUCCESS;
+ u64 = 0;
+ while ((uch = (unsigned char)*psz) != 0)
+ {
+ unsigned char chDigit = g_auchDigits[uch];
+ uint64_t u64Prev;
+
+ if (chDigit >= uBase)
+ break;
+
+ u64Prev = u64;
+ u64 *= uBase;
+ u64 += chDigit;
+ if (u64Prev > u64 || (u64Prev >> iShift))
+ rc = VWRN_NUMBER_TOO_BIG;
+ psz++;
+ }
+
+ if (!fPositive)
+ {
+ if (rc == VINF_SUCCESS)
+ rc = VWRN_NEGATIVE_UNSIGNED;
+ u64 = -(int64_t)u64;
+ }
+
+ if (pu64)
+ *pu64 = u64;
+
+ if (psz == pszValue)
+ rc = VERR_NO_DIGITS;
+
+ if (ppszNext)
+ *ppszNext = (char *)psz;
+
+ /*
+ * Warn about trailing chars/spaces.
+ */
+ if ( rc == VINF_SUCCESS
+ && *psz)
+ {
+ while (*psz == ' ' || *psz == '\t')
+ psz++;
+ rc = *psz ? VWRN_TRAILING_CHARS : VWRN_TRAILING_SPACES;
+ }
+
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTStrToUInt64Ex);
+
+
+/**
+ * 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 uBase The base of the representation used.
+ * If the function will look for known prefixes before defaulting to 10.
+ * @param pu64 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToUInt64Full(const char *pszValue, unsigned uBase, uint64_t *pu64)
+{
+ char *psz;
+ int rc = RTStrToUInt64Ex(pszValue, &psz, uBase, pu64);
+ if (RT_SUCCESS(rc) && *psz)
+ {
+ if (rc == VWRN_TRAILING_CHARS || rc == VWRN_TRAILING_SPACES)
+ rc = -rc;
+ else
+ {
+ while (*psz == ' ' || *psz == '\t')
+ psz++;
+ rc = *psz ? VERR_TRAILING_CHARS : VERR_TRAILING_SPACES;
+ }
+ }
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTStrToUInt64Full);
+
+
+/**
+ * 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)
+{
+ uint64_t u64;
+ int rc = RTStrToUInt64Ex(pszValue, NULL, 0, &u64);
+ if (RT_SUCCESS(rc))
+ return u64;
+ return 0;
+}
+RT_EXPORT_SYMBOL(RTStrToUInt64);
+
+
+/**
+ * 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 uBase The base of the representation used.
+ * If the function will look for known prefixes before defaulting to 10.
+ * @param pu32 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToUInt32Ex(const char *pszValue, char **ppszNext, unsigned uBase, uint32_t *pu32)
+{
+ uint64_t u64;
+ int rc = RTStrToUInt64Ex(pszValue, ppszNext, uBase, &u64);
+ if (RT_SUCCESS(rc))
+ {
+ if (u64 & ~0xffffffffULL)
+ rc = VWRN_NUMBER_TOO_BIG;
+ }
+ if (pu32)
+ *pu32 = (uint32_t)u64;
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTStrToUInt32Ex);
+
+
+/**
+ * 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 uBase The base of the representation used.
+ * If the function will look for known prefixes before defaulting to 10.
+ * @param pu32 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToUInt32Full(const char *pszValue, unsigned uBase, uint32_t *pu32)
+{
+ uint64_t u64;
+ int rc = RTStrToUInt64Full(pszValue, uBase, &u64);
+ if (RT_SUCCESS(rc))
+ {
+ if (u64 & ~0xffffffffULL)
+ rc = VWRN_NUMBER_TOO_BIG;
+ }
+ if (pu32)
+ *pu32 = (uint32_t)u64;
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTStrToUInt32Full);
+
+
+/**
+ * Converts a string representation of a number to a 64-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)
+{
+ uint32_t u32;
+ int rc = RTStrToUInt32Ex(pszValue, NULL, 0, &u32);
+ if (RT_SUCCESS(rc))
+ return u32;
+ return 0;
+}
+RT_EXPORT_SYMBOL(RTStrToUInt32);
+
+
+/**
+ * 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 uBase The base of the representation used.
+ * If the function will look for known prefixes before defaulting to 10.
+ * @param pu16 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToUInt16Ex(const char *pszValue, char **ppszNext, unsigned uBase, uint16_t *pu16)
+{
+ uint64_t u64;
+ int rc = RTStrToUInt64Ex(pszValue, ppszNext, uBase, &u64);
+ if (RT_SUCCESS(rc))
+ {
+ if (u64 & ~0xffffULL)
+ rc = VWRN_NUMBER_TOO_BIG;
+ }
+ if (pu16)
+ *pu16 = (uint16_t)u64;
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTStrToUInt16Ex);
+
+
+/**
+ * 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 uBase The base of the representation used.
+ * If the function will look for known prefixes before defaulting to 10.
+ * @param pu16 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToUInt16Full(const char *pszValue, unsigned uBase, uint16_t *pu16)
+{
+ uint64_t u64;
+ int rc = RTStrToUInt64Full(pszValue, uBase, &u64);
+ if (RT_SUCCESS(rc))
+ {
+ if (u64 & ~0xffffULL)
+ rc = VWRN_NUMBER_TOO_BIG;
+ }
+ if (pu16)
+ *pu16 = (uint16_t)u64;
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTStrToUInt16Full);
+
+
+/**
+ * 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)
+{
+ uint16_t u16;
+ int rc = RTStrToUInt16Ex(pszValue, NULL, 0, &u16);
+ if (RT_SUCCESS(rc))
+ return u16;
+ return 0;
+}
+RT_EXPORT_SYMBOL(RTStrToUInt16);
+
+
+/**
+ * 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 uBase The base of the representation used.
+ * If the function will look for known prefixes before defaulting to 10.
+ * @param pu8 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToUInt8Ex(const char *pszValue, char **ppszNext, unsigned uBase, uint8_t *pu8)
+{
+ uint64_t u64;
+ int rc = RTStrToUInt64Ex(pszValue, ppszNext, uBase, &u64);
+ if (RT_SUCCESS(rc))
+ {
+ if (u64 & ~0xffULL)
+ rc = VWRN_NUMBER_TOO_BIG;
+ }
+ if (pu8)
+ *pu8 = (uint8_t)u64;
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTStrToUInt8Ex);
+
+
+/**
+ * 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 uBase The base of the representation used.
+ * If the function will look for known prefixes before defaulting to 10.
+ * @param pu8 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToUInt8Full(const char *pszValue, unsigned uBase, uint8_t *pu8)
+{
+ uint64_t u64;
+ int rc = RTStrToUInt64Full(pszValue, uBase, &u64);
+ if (RT_SUCCESS(rc))
+ {
+ if (u64 & ~0xffULL)
+ rc = VWRN_NUMBER_TOO_BIG;
+ }
+ if (pu8)
+ *pu8 = (uint8_t)u64;
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTStrToUInt8Full);
+
+
+/**
+ * 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)
+{
+ uint8_t u8;
+ int rc = RTStrToUInt8Ex(pszValue, NULL, 0, &u8);
+ if (RT_SUCCESS(rc))
+ return u8;
+ return 0;
+}
+RT_EXPORT_SYMBOL(RTStrToUInt8);
+
+
+
+
+
+
+
+/**
+ * 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 uBase The base of the representation used.
+ * If the function will look for known prefixes before defaulting to 10.
+ * @param pi64 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToInt64Ex(const char *pszValue, char **ppszNext, unsigned uBase, int64_t *pi64)
+{
+ const char *psz = pszValue;
+ int iShift;
+ int rc;
+ int64_t i64;
+ unsigned char uch;
+
+ /*
+ * Positive/Negative stuff.
+ */
+ bool fPositive = true;
+ for (;; psz++)
+ {
+ if (*psz == '+')
+ fPositive = true;
+ else if (*psz == '-')
+ fPositive = !fPositive;
+ else
+ break;
+ }
+
+ /*
+ * Check for hex prefix.
+ */
+ if (!uBase)
+ {
+ if ( *psz == '0'
+ && (psz[1] == 'x' || psz[1] == 'X')
+ && g_auchDigits[(unsigned char)psz[2]] < 16)
+ {
+ uBase = 16;
+ psz += 2;
+ }
+ else if ( *psz == '0'
+ && g_auchDigits[(unsigned char)psz[1]] < 8)
+ {
+ uBase = 8;
+ psz++;
+ }
+ else
+ uBase = 10;
+ }
+ else if ( uBase == 16
+ && *psz == '0'
+ && (psz[1] == 'x' || psz[1] == 'X')
+ && g_auchDigits[(unsigned char)psz[2]] < 16)
+ psz += 2;
+
+ /*
+ * Interpret the value.
+ * Note: We only support ascii digits at this time... :-)
+ */
+ iShift = g_auchShift[uBase]; /** @todo test this, it's probably not 100% right yet. */
+ pszValue = psz; /* (Prefix and sign doesn't count in the digit counting.) */
+ rc = VINF_SUCCESS;
+ i64 = 0;
+ while ((uch = (unsigned char)*psz) != 0)
+ {
+ unsigned char chDigit = g_auchDigits[uch];
+ int64_t i64Prev;
+
+ if (chDigit >= uBase)
+ break;
+
+ i64Prev = i64;
+ i64 *= uBase;
+ i64 += chDigit;
+ if (i64Prev > i64 || (i64Prev >> iShift))
+ rc = VWRN_NUMBER_TOO_BIG;
+ psz++;
+ }
+
+ if (!fPositive)
+ i64 = -i64;
+
+ if (pi64)
+ *pi64 = i64;
+
+ if (psz == pszValue)
+ rc = VERR_NO_DIGITS;
+
+ if (ppszNext)
+ *ppszNext = (char *)psz;
+
+ /*
+ * Warn about trailing chars/spaces.
+ */
+ if ( rc == VINF_SUCCESS
+ && *psz)
+ {
+ while (*psz == ' ' || *psz == '\t')
+ psz++;
+ rc = *psz ? VWRN_TRAILING_CHARS : VWRN_TRAILING_SPACES;
+ }
+
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTStrToInt64Ex);
+
+
+/**
+ * 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 uBase The base of the representation used.
+ * If the function will look for known prefixes before defaulting to 10.
+ * @param pi64 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToInt64Full(const char *pszValue, unsigned uBase, int64_t *pi64)
+{
+ char *psz;
+ int rc = RTStrToInt64Ex(pszValue, &psz, uBase, pi64);
+ if (RT_SUCCESS(rc) && *psz)
+ {
+ if (rc == VWRN_TRAILING_CHARS || rc == VWRN_TRAILING_SPACES)
+ rc = -rc;
+ else
+ {
+ while (*psz == ' ' || *psz == '\t')
+ psz++;
+ rc = *psz ? VERR_TRAILING_CHARS : VERR_TRAILING_SPACES;
+ }
+ }
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTStrToInt64Full);
+
+
+/**
+ * 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)
+{
+ int64_t i64;
+ int rc = RTStrToInt64Ex(pszValue, NULL, 0, &i64);
+ if (RT_SUCCESS(rc))
+ return i64;
+ return 0;
+}
+RT_EXPORT_SYMBOL(RTStrToInt64);
+
+
+/**
+ * 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 uBase The base of the representation used.
+ * If the function will look for known prefixes before defaulting to 10.
+ * @param pi32 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToInt32Ex(const char *pszValue, char **ppszNext, unsigned uBase, int32_t *pi32)
+{
+ int64_t i64;
+ int rc = RTStrToInt64Ex(pszValue, ppszNext, uBase, &i64);
+ if (RT_SUCCESS(rc))
+ {
+ int32_t i32 = (int32_t)i64;
+ if (i64 != (int64_t)i32)
+ rc = VWRN_NUMBER_TOO_BIG;
+ }
+ if (pi32)
+ *pi32 = (int32_t)i64;
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTStrToInt32Ex);
+
+
+/**
+ * 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 uBase The base of the representation used.
+ * If the function will look for known prefixes before defaulting to 10.
+ * @param pi32 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToInt32Full(const char *pszValue, unsigned uBase, int32_t *pi32)
+{
+ int64_t i64;
+ int rc = RTStrToInt64Full(pszValue, uBase, &i64);
+ if (RT_SUCCESS(rc))
+ {
+ int32_t i32 = (int32_t)i64;
+ if (i64 != (int64_t)i32)
+ rc = VWRN_NUMBER_TOO_BIG;
+ }
+ if (pi32)
+ *pi32 = (int32_t)i64;
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTStrToInt32Full);
+
+
+/**
+ * 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)
+{
+ int32_t i32;
+ int rc = RTStrToInt32Ex(pszValue, NULL, 0, &i32);
+ if (RT_SUCCESS(rc))
+ return i32;
+ return 0;
+}
+RT_EXPORT_SYMBOL(RTStrToInt32);
+
+
+/**
+ * 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 uBase The base of the representation used.
+ * If the function will look for known prefixes before defaulting to 10.
+ * @param pi16 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToInt16Ex(const char *pszValue, char **ppszNext, unsigned uBase, int16_t *pi16)
+{
+ int64_t i64;
+ int rc = RTStrToInt64Ex(pszValue, ppszNext, uBase, &i64);
+ if (RT_SUCCESS(rc))
+ {
+ int16_t i16 = (int16_t)i64;
+ if (i64 != (int64_t)i16)
+ rc = VWRN_NUMBER_TOO_BIG;
+ }
+ if (pi16)
+ *pi16 = (int16_t)i64;
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTStrToInt16Ex);
+
+
+/**
+ * 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 uBase The base of the representation used.
+ * If the function will look for known prefixes before defaulting to 10.
+ * @param pi16 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToInt16Full(const char *pszValue, unsigned uBase, int16_t *pi16)
+{
+ int64_t i64;
+ int rc = RTStrToInt64Full(pszValue, uBase, &i64);
+ if (RT_SUCCESS(rc))
+ {
+ int16_t i16 = (int16_t)i64;
+ if (i64 != (int64_t)i16)
+ rc = VWRN_NUMBER_TOO_BIG;
+ }
+ if (pi16)
+ *pi16 = (int16_t)i64;
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTStrToInt16Full);
+
+
+/**
+ * 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)
+{
+ int16_t i16;
+ int rc = RTStrToInt16Ex(pszValue, NULL, 0, &i16);
+ if (RT_SUCCESS(rc))
+ return i16;
+ return 0;
+}
+RT_EXPORT_SYMBOL(RTStrToInt16);
+
+
+/**
+ * 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 uBase The base of the representation used.
+ * If the function will look for known prefixes before defaulting to 10.
+ * @param pi8 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToInt8Ex(const char *pszValue, char **ppszNext, unsigned uBase, int8_t *pi8)
+{
+ int64_t i64;
+ int rc = RTStrToInt64Ex(pszValue, ppszNext, uBase, &i64);
+ if (RT_SUCCESS(rc))
+ {
+ int8_t i8 = (int8_t)i64;
+ if (i64 != (int64_t)i8)
+ rc = VWRN_NUMBER_TOO_BIG;
+ }
+ if (pi8)
+ *pi8 = (int8_t)i64;
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTStrToInt8Ex);
+
+
+/**
+ * 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 uBase The base of the representation used.
+ * If the function will look for known prefixes before defaulting to 10.
+ * @param pi8 Where to store the converted number. (optional)
+ */
+RTDECL(int) RTStrToInt8Full(const char *pszValue, unsigned uBase, int8_t *pi8)
+{
+ int64_t i64;
+ int rc = RTStrToInt64Full(pszValue, uBase, &i64);
+ if (RT_SUCCESS(rc))
+ {
+ int8_t i8 = (int8_t)i64;
+ if (i64 != (int64_t)i8)
+ rc = VWRN_NUMBER_TOO_BIG;
+ }
+ if (pi8)
+ *pi8 = (int8_t)i64;
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTStrToInt8Full);
+
+
+/**
+ * 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)
+{
+ int8_t i8;
+ int rc = RTStrToInt8Ex(pszValue, NULL, 0, &i8);
+ if (RT_SUCCESS(rc))
+ return i8;
+ return 0;
+}
+RT_EXPORT_SYMBOL(RTStrToInt8);
+
+
+RTDECL(int) RTStrConvertHexBytes(char const *pszHex, void *pv, size_t cb, uint32_t fFlags)
+{
+ size_t cbDst;
+ uint8_t *pbDst;
+ const char *pszSrc;
+
+ AssertPtrReturn(pszHex, VERR_INVALID_POINTER);
+ AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
+
+ cbDst = cb;
+ pbDst = (uint8_t *)pv;
+ pszSrc = pszHex;
+ for (;;)
+ {
+ /* Pick the next two digit from the string. */
+ char ch = *pszSrc++;
+ unsigned char uchDigit1 = g_auchDigits[(unsigned char)ch];
+ unsigned char uchDigit2;
+ if (uchDigit1 >= 16)
+ {
+ if (!ch)
+ return cbDst == 0 ? VINF_SUCCESS : VERR_BUFFER_UNDERFLOW;
+
+ while (ch == ' ' || ch == '\t')
+ ch = *pszSrc++;
+ return ch ? VWRN_TRAILING_CHARS : VWRN_TRAILING_SPACES;
+ }
+
+ ch = *pszSrc++;
+ uchDigit2 = g_auchDigits[(unsigned char)ch];
+ if (uchDigit2 >= 16)
+ return VERR_UNEVEN_INPUT;
+
+ /* Add the byte to the output buffer. */
+ if (!cbDst)
+ return VERR_BUFFER_OVERFLOW;
+ cbDst--;
+ *pbDst++ = (uchDigit1 << 4) | uchDigit2;
+ }
+}
+RT_EXPORT_SYMBOL(RTStrConvertHexBytes);
+
--- /dev/null
+/* $Id: avl_Base.cpp.h $ */
+/** @file
+ * kAVLBase - basic routines for all AVL trees.
+ */
+
+/*
+ * Copyright (C) 2006-2017 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef _kAVLBase_h_
+#define _kAVLBase_h_
+
+
+/** @page pg_rt_kAVL kAVL Template configuration.
+ * @internal
+ *
+ * This is a template made to implement multiple AVL trees. The differences
+ * among the implementations are related to the key used.
+ *
+ * \#define KAVL_FN
+ * Use this to alter the names of the AVL functions.
+ * Must be defined.
+ *
+ * \#define KAVL_EQUAL_ALLOWED
+ * Define this to tell us that equal keys are allowed.
+ * Then Equal keys will be put in a list pointed to by pList in the KAVLNODECORE.
+ * This is by default not defined.
+ *
+ * \#define KAVL_CHECK_FOR_EQUAL_INSERT
+ * Define this to enable insert check for equal nodes.
+ * This is by default not defined.
+ *
+ * \#define KAVL_MAX_STACK
+ * Use this to specify the number of stack entries the stack will use when inserting
+ * and removing nodes from the tree. I think the size should be about
+ * log2(<max nodes>) + 3
+ * Must be defined.
+ *
+ */
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+#define AVL_HEIGHTOF(pNode) ((unsigned char)((pNode) != NULL ? pNode->uchHeight : 0))
+
+/** @def KAVL_GET_POINTER
+ * Reads a 'pointer' value.
+ *
+ * @returns The native pointer.
+ * @param pp Pointer to the pointer to read.
+ */
+
+/** @def KAVL_GET_POINTER_NULL
+ * Reads a 'pointer' value which can be KAVL_NULL.
+ *
+ * @returns The native pointer.
+ * @returns NULL pointer if KAVL_NULL.
+ * @param pp Pointer to the pointer to read.
+ */
+
+/** @def KAVL_SET_POINTER
+ * Writes a 'pointer' value.
+ * For offset-based schemes offset relative to pp is calculated and assigned to *pp.
+ *
+ * @returns stored pointer.
+ * @param pp Pointer to where to store the pointer.
+ * @param p Native pointer to assign to *pp.
+ */
+
+/** @def KAVL_SET_POINTER_NULL
+ * Writes a 'pointer' value which can be KAVL_NULL.
+ *
+ * For offset-based schemes offset relative to pp is calculated and assigned to *pp,
+ * if p is not KAVL_NULL of course.
+ *
+ * @returns stored pointer.
+ * @param pp Pointer to where to store the pointer.
+ * @param pp2 Pointer to where to pointer to assign to pp. This can be KAVL_NULL
+ */
+
+#ifndef KAVL_GET_POINTER
+# ifdef KAVL_OFFSET
+# define KAVL_GET_POINTER(pp) ( (PKAVLNODECORE)((intptr_t)(pp) + *(pp)) )
+# define KAVL_GET_POINTER_NULL(pp) ( *(pp) != KAVL_NULL ? KAVL_GET_POINTER(pp) : NULL )
+# define KAVL_SET_POINTER(pp, p) ( (*(pp)) = ((intptr_t)(p) - (intptr_t)(pp)) )
+# define KAVL_SET_POINTER_NULL(pp, pp2) ( (*(pp)) = *(pp2) != KAVL_NULL ? (intptr_t)KAVL_GET_POINTER(pp2) - (intptr_t)(pp) : KAVL_NULL )
+# else
+# define KAVL_GET_POINTER(pp) ( *(pp) )
+# define KAVL_GET_POINTER_NULL(pp) ( *(pp) )
+# define KAVL_SET_POINTER(pp, p) ( (*(pp)) = (p) )
+# define KAVL_SET_POINTER_NULL(pp, pp2) ( (*(pp)) = *(pp2) )
+# endif
+#endif
+
+
+/** @def KAVL_NULL
+ * The NULL 'pointer' equivalent.
+ */
+#ifndef KAVL_NULL
+# ifdef KAVL_OFFSET
+# define KAVL_NULL 0
+# else
+# define KAVL_NULL NULL
+# endif
+#endif
+
+#ifndef KAVL_RANGE
+# define KAVL_R_IS_INTERSECTING(key1B, key2B, key1E, key2E) KAVL_E(key1B, key2B)
+# define KAVL_R_IS_IDENTICAL(key1B, key2B, key1E, key2E) KAVL_E(key1B, key2B)
+#endif
+
+/** @def KAVL_DECL
+ * Function declation macro in the RTDECL tradition.
+ * @param a_Type The function return type. */
+#ifndef KAVL_DECL
+# define KAVL_DECL(a_Type) RTDECL(a_Type)
+#endif
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/*
+ * A stack used to avoid recursive calls...
+ */
+typedef struct _kAvlStack
+{
+ unsigned cEntries;
+ PPKAVLNODECORE aEntries[KAVL_MAX_STACK];
+} KAVLSTACK, *PKAVLSTACK;
+
+typedef struct _kAvlStack2
+{
+ unsigned cEntries;
+ PKAVLNODECORE aEntries[KAVL_MAX_STACK];
+ char achFlags[KAVL_MAX_STACK];
+} KAVLSTACK2, *PLAVLSTACK2;
+
+
+
+/**
+ * Rewinds a stack of pointers to pointers to nodes, rebalancing the tree.
+ * @param pStack Pointer to stack to rewind.
+ * @sketch 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
+ */
+DECLINLINE(void) KAVL_FN(Rebalance)(PKAVLSTACK pStack)
+{
+ while (pStack->cEntries > 0)
+ {
+ /** @todo Perhaps some of these KAVL_SET_POINTER_NULL() cases could be optimized away.. */
+ PPKAVLNODECORE ppNode = pStack->aEntries[--pStack->cEntries];
+ PKAVLNODECORE pNode = KAVL_GET_POINTER(ppNode);
+ PKAVLNODECORE pLeftNode = KAVL_GET_POINTER_NULL(&pNode->pLeft);
+ unsigned char uchLeftHeight = AVL_HEIGHTOF(pLeftNode);
+ PKAVLNODECORE pRightNode = KAVL_GET_POINTER_NULL(&pNode->pRight);
+ unsigned char uchRightHeight = AVL_HEIGHTOF(pRightNode);
+
+ if (uchRightHeight + 1 < uchLeftHeight)
+ {
+ PKAVLNODECORE pLeftLeftNode = KAVL_GET_POINTER_NULL(&pLeftNode->pLeft);
+ PKAVLNODECORE pLeftRightNode = KAVL_GET_POINTER_NULL(&pLeftNode->pRight);
+ unsigned char uchLeftRightHeight = AVL_HEIGHTOF(pLeftRightNode);
+
+ if (AVL_HEIGHTOF(pLeftLeftNode) >= uchLeftRightHeight)
+ {
+ KAVL_SET_POINTER_NULL(&pNode->pLeft, &pLeftNode->pRight);
+ KAVL_SET_POINTER(&pLeftNode->pRight, pNode);
+ pLeftNode->uchHeight = (unsigned char)(1 + (pNode->uchHeight = (unsigned char)(1 + uchLeftRightHeight)));
+ KAVL_SET_POINTER(ppNode, pLeftNode);
+ }
+ else
+ {
+ KAVL_SET_POINTER_NULL(&pLeftNode->pRight, &pLeftRightNode->pLeft);
+ KAVL_SET_POINTER_NULL(&pNode->pLeft, &pLeftRightNode->pRight);
+ KAVL_SET_POINTER(&pLeftRightNode->pLeft, pLeftNode);
+ KAVL_SET_POINTER(&pLeftRightNode->pRight, pNode);
+ pLeftNode->uchHeight = pNode->uchHeight = uchLeftRightHeight;
+ pLeftRightNode->uchHeight = uchLeftHeight;
+ KAVL_SET_POINTER(ppNode, pLeftRightNode);
+ }
+ }
+ else if (uchLeftHeight + 1 < uchRightHeight)
+ {
+ PKAVLNODECORE pRightLeftNode = KAVL_GET_POINTER_NULL(&pRightNode->pLeft);
+ unsigned char uchRightLeftHeight = AVL_HEIGHTOF(pRightLeftNode);
+ PKAVLNODECORE pRightRightNode = KAVL_GET_POINTER_NULL(&pRightNode->pRight);
+
+ if (AVL_HEIGHTOF(pRightRightNode) >= uchRightLeftHeight)
+ {
+ KAVL_SET_POINTER_NULL(&pNode->pRight, &pRightNode->pLeft);
+ KAVL_SET_POINTER(&pRightNode->pLeft, pNode);
+ pRightNode->uchHeight = (unsigned char)(1 + (pNode->uchHeight = (unsigned char)(1 + uchRightLeftHeight)));
+ KAVL_SET_POINTER(ppNode, pRightNode);
+ }
+ else
+ {
+ KAVL_SET_POINTER_NULL(&pRightNode->pLeft, &pRightLeftNode->pRight);
+ KAVL_SET_POINTER_NULL(&pNode->pRight, &pRightLeftNode->pLeft);
+ KAVL_SET_POINTER(&pRightLeftNode->pRight, pRightNode);
+ KAVL_SET_POINTER(&pRightLeftNode->pLeft, pNode);
+ pRightNode->uchHeight = pNode->uchHeight = uchRightLeftHeight;
+ pRightLeftNode->uchHeight = uchRightHeight;
+ KAVL_SET_POINTER(ppNode, pRightLeftNode);
+ }
+ }
+ else
+ {
+ register unsigned char uchHeight = (unsigned char)(KMAX(uchLeftHeight, uchRightHeight) + 1);
+ if (uchHeight == pNode->uchHeight)
+ break;
+ pNode->uchHeight = uchHeight;
+ }
+ }
+
+}
+
+
+
+
+/**
+ * Inserts a node into the AVL-tree.
+ * @returns TRUE if inserted.
+ * FALSE if node exists in tree.
+ * @param ppTree Pointer to the AVL-tree root node pointer.
+ * @param pNode Pointer to the node which is to be added.
+ * @sketch 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.
+ */
+KAVL_DECL(bool) KAVL_FN(Insert)(PPKAVLNODECORE ppTree, PKAVLNODECORE pNode)
+{
+ KAVLSTACK AVLStack;
+ PPKAVLNODECORE ppCurNode = ppTree;
+ register PKAVLNODECORE pCurNode;
+ register KAVLKEY Key = pNode->Key; NOREF(Key);
+#ifdef KAVL_RANGE
+ register KAVLKEY KeyLast = pNode->KeyLast; NOREF(KeyLast);
+#endif
+
+ AVLStack.cEntries = 0;
+
+#ifdef KAVL_RANGE
+ if (Key > KeyLast)
+ return false;
+#endif
+
+ for (;;)
+ {
+ if (*ppCurNode != KAVL_NULL)
+ pCurNode = KAVL_GET_POINTER(ppCurNode);
+ else
+ break;
+
+ kASSERT(AVLStack.cEntries < KAVL_MAX_STACK);
+ AVLStack.aEntries[AVLStack.cEntries++] = ppCurNode;
+#ifdef KAVL_EQUAL_ALLOWED
+ if (KAVL_R_IS_IDENTICAL(pCurNode->Key, Key, pCurNode->KeyLast, KeyLast))
+ {
+ /*
+ * If equal then we'll use a list of equal nodes.
+ */
+ pNode->pLeft = pNode->pRight = KAVL_NULL;
+ pNode->uchHeight = 0;
+ KAVL_SET_POINTER_NULL(&pNode->pList, &pCurNode->pList);
+ KAVL_SET_POINTER(&pCurNode->pList, pNode);
+ return true;
+ }
+#endif
+#ifdef KAVL_CHECK_FOR_EQUAL_INSERT
+ if (KAVL_R_IS_INTERSECTING(pCurNode->Key, Key, pCurNode->KeyLast, KeyLast))
+ return false;
+#endif
+ if (KAVL_G(pCurNode->Key, Key))
+ ppCurNode = &pCurNode->pLeft;
+ else
+ ppCurNode = &pCurNode->pRight;
+ }
+
+ pNode->pLeft = pNode->pRight = KAVL_NULL;
+#ifdef KAVL_EQUAL_ALLOWED
+ pNode->pList = KAVL_NULL;
+#endif
+ pNode->uchHeight = 1;
+ KAVL_SET_POINTER(ppCurNode, pNode);
+
+ KAVL_FN(Rebalance)(SSToDS(&AVLStack));
+ return true;
+}
+
+
+/**
+ * Removes a node from the AVL-tree.
+ * @returns Pointer to the node.
+ * @param ppTree Pointer to the AVL-tree root node pointer.
+ * @param Key Key value of the node which is to be removed.
+ * @sketch 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).
+ */
+KAVL_DECL(PKAVLNODECORE) KAVL_FN(Remove)(PPKAVLNODECORE ppTree, KAVLKEY Key)
+{
+ KAVLSTACK AVLStack;
+ PPKAVLNODECORE ppDeleteNode = ppTree;
+ register PKAVLNODECORE pDeleteNode;
+
+ AVLStack.cEntries = 0;
+
+ for (;;)
+ {
+ if (*ppDeleteNode != KAVL_NULL)
+ pDeleteNode = KAVL_GET_POINTER(ppDeleteNode);
+ else
+ return NULL;
+
+ kASSERT(AVLStack.cEntries < KAVL_MAX_STACK);
+ AVLStack.aEntries[AVLStack.cEntries++] = ppDeleteNode;
+ if (KAVL_E(pDeleteNode->Key, Key))
+ break;
+
+ if (KAVL_G(pDeleteNode->Key, Key))
+ ppDeleteNode = &pDeleteNode->pLeft;
+ else
+ ppDeleteNode = &pDeleteNode->pRight;
+ }
+
+ if (pDeleteNode->pLeft != KAVL_NULL)
+ {
+ /* find the rightmost node in the left tree. */
+ const unsigned iStackEntry = AVLStack.cEntries;
+ PPKAVLNODECORE ppLeftLeast = &pDeleteNode->pLeft;
+ register PKAVLNODECORE pLeftLeast = KAVL_GET_POINTER(ppLeftLeast);
+
+ while (pLeftLeast->pRight != KAVL_NULL)
+ {
+ kASSERT(AVLStack.cEntries < KAVL_MAX_STACK);
+ AVLStack.aEntries[AVLStack.cEntries++] = ppLeftLeast;
+ ppLeftLeast = &pLeftLeast->pRight;
+ pLeftLeast = KAVL_GET_POINTER(ppLeftLeast);
+ }
+
+ /* link out pLeftLeast */
+ KAVL_SET_POINTER_NULL(ppLeftLeast, &pLeftLeast->pLeft);
+
+ /* link it in place of the delete node. */
+ KAVL_SET_POINTER_NULL(&pLeftLeast->pLeft, &pDeleteNode->pLeft);
+ KAVL_SET_POINTER_NULL(&pLeftLeast->pRight, &pDeleteNode->pRight);
+ pLeftLeast->uchHeight = pDeleteNode->uchHeight;
+ KAVL_SET_POINTER(ppDeleteNode, pLeftLeast);
+ AVLStack.aEntries[iStackEntry] = &pLeftLeast->pLeft;
+ }
+ else
+ {
+ KAVL_SET_POINTER_NULL(ppDeleteNode, &pDeleteNode->pRight);
+ AVLStack.cEntries--;
+ }
+
+ KAVL_FN(Rebalance)(SSToDS(&AVLStack));
+ return pDeleteNode;
+}
+
+#endif
--- /dev/null
+/* $Id: avl_Destroy.cpp.h $ */
+/** @file
+ * kAVLDestroy - Walk the tree calling a callback to destroy all the nodes.
+ */
+
+/*
+ * Copyright (C) 2006-2017 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef _kAVLDestroy_h_
+#define _kAVLDestroy_h_
+
+
+/**
+ * Destroys the specified tree, starting with the root node and working our way down.
+ *
+ * @returns 0 on success.
+ * @returns Return value from callback on failure. On failure, the tree will be in
+ * an unbalanced condition and only further calls to the Destroy should be
+ * made on it. Note that the node we fail on will be considered dead and
+ * no action is taken to link it back into the tree.
+ * @param ppTree Pointer to the AVL-tree root node pointer.
+ * @param pfnCallBack Pointer to callback function.
+ * @param pvUser User parameter passed on to the callback function.
+ */
+KAVL_DECL(int) KAVL_FN(Destroy)(PPKAVLNODECORE ppTree, PKAVLCALLBACK pfnCallBack, void *pvUser)
+{
+ unsigned cEntries;
+ PKAVLNODECORE apEntries[KAVL_MAX_STACK];
+ int rc;
+
+ if (*ppTree == KAVL_NULL)
+ return VINF_SUCCESS;
+
+ cEntries = 1;
+ apEntries[0] = KAVL_GET_POINTER(ppTree);
+ while (cEntries > 0)
+ {
+ /*
+ * Process the subtrees first.
+ */
+ PKAVLNODECORE pNode = apEntries[cEntries - 1];
+ if (pNode->pLeft != KAVL_NULL)
+ apEntries[cEntries++] = KAVL_GET_POINTER(&pNode->pLeft);
+ else if (pNode->pRight != KAVL_NULL)
+ apEntries[cEntries++] = KAVL_GET_POINTER(&pNode->pRight);
+ else
+ {
+#ifdef KAVL_EQUAL_ALLOWED
+ /*
+ * Process nodes with the same key.
+ */
+ while (pNode->pList != KAVL_NULL)
+ {
+ PKAVLNODECORE pEqual = KAVL_GET_POINTER(&pNode->pList);
+ KAVL_SET_POINTER(&pNode->pList, KAVL_GET_POINTER_NULL(&pEqual->pList));
+ pEqual->pList = KAVL_NULL;
+
+ rc = pfnCallBack(pEqual, pvUser);
+ if (rc != VINF_SUCCESS)
+ return rc;
+ }
+#endif
+
+ /*
+ * Unlink the node.
+ */
+ if (--cEntries > 0)
+ {
+ PKAVLNODECORE pParent = apEntries[cEntries - 1];
+ if (KAVL_GET_POINTER(&pParent->pLeft) == pNode)
+ pParent->pLeft = KAVL_NULL;
+ else
+ pParent->pRight = KAVL_NULL;
+ }
+ else
+ *ppTree = KAVL_NULL;
+
+ kASSERT(pNode->pLeft == KAVL_NULL);
+ kASSERT(pNode->pRight == KAVL_NULL);
+ rc = pfnCallBack(pNode, pvUser);
+ if (rc != VINF_SUCCESS)
+ return rc;
+ }
+ } /* while */
+
+ kASSERT(*ppTree == KAVL_NULL);
+
+ return VINF_SUCCESS;
+}
+
+#endif
+
--- /dev/null
+/* $Id: avl_DoWithAll.cpp.h $ */
+/** @file
+ * kAVLDoWithAll - Do with all nodes routine for AVL trees.
+ */
+
+/*
+ * Copyright (C) 2006-2017 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef _kAVLDoWithAll_h_
+#define _kAVLDoWithAll_h_
+
+
+/**
+ * Iterates thru all nodes in the given tree.
+ * @returns 0 on success. Return from callback on failure.
+ * @param ppTree Pointer to the AVL-tree root node pointer.
+ * @param fFromLeft TRUE: Left to right.
+ * FALSE: Right to left.
+ * @param pfnCallBack Pointer to callback function.
+ * @param pvParam Userparameter passed on to the callback function.
+ */
+KAVL_DECL(int) KAVL_FN(DoWithAll)(PPKAVLNODECORE ppTree, int fFromLeft, PKAVLCALLBACK pfnCallBack, void * pvParam)
+{
+ KAVLSTACK2 AVLStack;
+ PKAVLNODECORE pNode;
+#ifdef KAVL_EQUAL_ALLOWED
+ PKAVLNODECORE pEqual;
+#endif
+ int rc;
+
+ if (*ppTree == KAVL_NULL)
+ return VINF_SUCCESS;
+
+ AVLStack.cEntries = 1;
+ AVLStack.achFlags[0] = 0;
+ AVLStack.aEntries[0] = KAVL_GET_POINTER(ppTree);
+
+ if (fFromLeft)
+ { /* from left */
+ while (AVLStack.cEntries > 0)
+ {
+ pNode = AVLStack.aEntries[AVLStack.cEntries - 1];
+
+ /* left */
+ if (!AVLStack.achFlags[AVLStack.cEntries - 1]++)
+ {
+ if (pNode->pLeft != KAVL_NULL)
+ {
+ AVLStack.achFlags[AVLStack.cEntries] = 0; /* 0 first, 1 last */
+ AVLStack.aEntries[AVLStack.cEntries++] = KAVL_GET_POINTER(&pNode->pLeft);
+ continue;
+ }
+ }
+
+ /* center */
+ rc = pfnCallBack(pNode, pvParam);
+ if (rc != VINF_SUCCESS)
+ return rc;
+#ifdef KAVL_EQUAL_ALLOWED
+ if (pNode->pList != KAVL_NULL)
+ for (pEqual = KAVL_GET_POINTER(&pNode->pList); pEqual; pEqual = KAVL_GET_POINTER_NULL(&pEqual->pList))
+ {
+ rc = pfnCallBack(pEqual, pvParam);
+ if (rc != VINF_SUCCESS)
+ return rc;
+ }
+#endif
+
+ /* right */
+ AVLStack.cEntries--;
+ if (pNode->pRight != KAVL_NULL)
+ {
+ AVLStack.achFlags[AVLStack.cEntries] = 0;
+ AVLStack.aEntries[AVLStack.cEntries++] = KAVL_GET_POINTER(&pNode->pRight);
+ }
+ } /* while */
+ }
+ else
+ { /* from right */
+ while (AVLStack.cEntries > 0)
+ {
+ pNode = AVLStack.aEntries[AVLStack.cEntries - 1];
+
+ /* right */
+ if (!AVLStack.achFlags[AVLStack.cEntries - 1]++)
+ {
+ if (pNode->pRight != KAVL_NULL)
+ {
+ AVLStack.achFlags[AVLStack.cEntries] = 0; /* 0 first, 1 last */
+ AVLStack.aEntries[AVLStack.cEntries++] = KAVL_GET_POINTER(&pNode->pRight);
+ continue;
+ }
+ }
+
+ /* center */
+ rc = pfnCallBack(pNode, pvParam);
+ if (rc != VINF_SUCCESS)
+ return rc;
+#ifdef KAVL_EQUAL_ALLOWED
+ if (pNode->pList != KAVL_NULL)
+ for (pEqual = KAVL_GET_POINTER(&pNode->pList); pEqual; pEqual = KAVL_GET_POINTER_NULL(&pEqual->pList))
+ {
+ rc = pfnCallBack(pEqual, pvParam);
+ if (rc != VINF_SUCCESS)
+ return rc;
+ }
+#endif
+
+ /* left */
+ AVLStack.cEntries--;
+ if (pNode->pLeft != KAVL_NULL)
+ {
+ AVLStack.achFlags[AVLStack.cEntries] = 0;
+ AVLStack.aEntries[AVLStack.cEntries++] = KAVL_GET_POINTER(&pNode->pLeft);
+ }
+ } /* while */
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+#endif
+
--- /dev/null
+/* $Id: avl_Get.cpp.h $ */
+/** @file
+ * kAVLGet - get routine for AVL trees.
+ */
+
+/*
+ * Copyright (C) 2006-2017 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef _kAVLGet_h_
+#define _kAVLGet_h_
+
+
+/**
+ * Gets a node from the tree (does not remove it!)
+ * @returns Pointer to the node holding the given key.
+ * @param ppTree Pointer to the AVL-tree root node pointer.
+ * @param Key Key value of the node which is to be found.
+ * @author knut st. osmundsen
+ */
+KAVL_DECL(PKAVLNODECORE) KAVL_FN(Get)(PPKAVLNODECORE ppTree, KAVLKEY Key)
+{
+ register PKAVLNODECORE pNode = KAVL_GET_POINTER_NULL(ppTree);
+
+ if (pNode)
+ {
+ while (KAVL_NE(pNode->Key, Key))
+ {
+ if (KAVL_G(pNode->Key, Key))
+ {
+ if (pNode->pLeft != KAVL_NULL)
+ pNode = KAVL_GET_POINTER(&pNode->pLeft);
+ else
+ return NULL;
+ }
+ else
+ {
+ if (pNode->pRight != KAVL_NULL)
+ pNode = KAVL_GET_POINTER(&pNode->pRight);
+ else
+ return NULL;
+ }
+ }
+ }
+
+ return pNode;
+}
+
+
+#endif
--- /dev/null
+/* $Id: avl_GetBestFit.cpp.h $ */
+/** @file
+ * kAVLGetBestFit - Get Best Fit routine for AVL trees.
+ * Intended specially on heaps. The tree should allow duplicate keys.
+ *
+ */
+
+/*
+ * Copyright (C) 2006-2017 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef _kAVLGetBestFit_h_
+#define _kAVLGetBestFit_h_
+
+
+/**
+ * Finds the best fitting node in the tree for the given Key value.
+ * @returns Pointer to the best fitting node found.
+ * @param ppTree Pointer to Pointer to the tree root node.
+ * @param Key The Key of which is to be found a best fitting match for..
+ * @param fAbove TRUE: Returned node is have the closest key to Key from above.
+ * FALSE: Returned node is have the closest key to Key from below.
+ * @sketch The best fitting node is always located in the searchpath above you.
+ * >= (above): The node where you last turned left.
+ * <= (below): the node where you last turned right.
+ */
+KAVL_DECL(PKAVLNODECORE) KAVL_FN(GetBestFit)(PPKAVLNODECORE ppTree, KAVLKEY Key, bool fAbove)
+{
+ register PKAVLNODECORE pNode = KAVL_GET_POINTER_NULL(ppTree);
+ if (pNode)
+ {
+ PKAVLNODECORE pNodeLast = NULL;
+ if (fAbove)
+ { /* pNode->Key >= Key */
+ while (KAVL_NE(pNode->Key, Key))
+ {
+ if (KAVL_G(pNode->Key, Key))
+ {
+ if (pNode->pLeft != KAVL_NULL)
+ {
+ pNodeLast = pNode;
+ pNode = KAVL_GET_POINTER(&pNode->pLeft);
+ }
+ else
+ return pNode;
+ }
+ else
+ {
+ if (pNode->pRight != KAVL_NULL)
+ pNode = KAVL_GET_POINTER(&pNode->pRight);
+ else
+ return pNodeLast;
+ }
+ }
+ }
+ else
+ { /* pNode->Key <= Key */
+ while (KAVL_NE(pNode->Key, Key))
+ {
+ if (KAVL_G(pNode->Key, Key))
+ {
+ if (pNode->pLeft != KAVL_NULL)
+ pNode = KAVL_GET_POINTER(&pNode->pLeft);
+ else
+ return pNodeLast;
+ }
+ else
+ {
+ if (pNode->pRight != KAVL_NULL)
+ {
+ pNodeLast = pNode;
+ pNode = KAVL_GET_POINTER(&pNode->pRight);
+ }
+ else
+ return pNode;
+ }
+ }
+ }
+ }
+
+ /* perfect match or nothing. */
+ return pNode;
+}
+
+
+#endif
--- /dev/null
+/* $Id: avl_RemoveBestFit.cpp.h $ */
+/** @file
+ * kAVLRemoveBestFit - Remove Best Fit routine for AVL trees.
+ * Intended specially on heaps. The tree should allow duplicate keys.
+ *
+ */
+
+/*
+ * Copyright (C) 2006-2017 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef _kAVLRemoveBestFit_h_
+#define _kAVLRemoveBestFit_h_
+
+
+/**
+ * Finds the best fitting node in the tree for the given Key value.
+ * And removes it.
+ * @returns Pointer to the best fitting node found.
+ * @param ppTree Pointer to Pointer to the tree root node.
+ * @param Key The Key of which is to be found a best fitting match for..
+ * @param fAbove TRUE: Returned node is have the closest key to Key from above.
+ * FALSE: Returned node is have the closest key to Key from below.
+ * @sketch The best fitting node is always located in the searchpath above you.
+ * >= (above): The node where you last turned left.
+ * <= (below): the node where you last turned right.
+ * @remark This implementation should be speeded up slightly!
+ */
+KAVL_DECL(PKAVLNODECORE) KAVL_FN(RemoveBestFit)(PPKAVLNODECORE ppTree, KAVLKEY Key, bool fAbove)
+{
+ /*
+ * If we find anything we'll have to remove the node and return it.
+ * But, if duplicate keys are allowed we'll have to check for multiple
+ * nodes first and return one of them before doing an expensive remove+insert.
+ */
+ PKAVLNODECORE pNode = KAVL_FN(GetBestFit)(ppTree, Key, fAbove);
+ if (pNode != NULL)
+ {
+#ifdef KAVL_EQUAL_ALLOWED
+ if (pNode->pList != KAVL_NULL)
+ {
+ PKAVLNODECORE pRet = KAVL_GET_POINTER(&pNode->pList);
+ KAVL_SET_POINTER_NULL(&pNode->pList, &pRet->pList);
+ return pRet;
+ }
+#endif
+ pNode = KAVL_FN(Remove)(ppTree, pNode->Key);
+ }
+ return pNode;
+}
+
+
+#endif
--- /dev/null
+/* $Id: avlpv.cpp $ */
+/** @file
+ * IPRT - AVL tree, void *, unique keys.
+ */
+
+/*
+ * Copyright (C) 2006-2017 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef NOFILEID
+static const char szFileId[] = "Id: kAVLPVInt.c,v 1.5 2003/02/13 02:02:35 bird Exp $";
+#endif
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/*
+ * AVL configuration.
+ */
+#define KAVL_FN(a) RTAvlPV##a
+#define KAVL_MAX_STACK 27 /* Up to 2^24 nodes. */
+#define KAVL_CHECK_FOR_EQUAL_INSERT 1 /* No duplicate keys! */
+#define KAVLNODECORE AVLPVNODECORE
+#define PKAVLNODECORE PAVLPVNODECORE
+#define PPKAVLNODECORE PPAVLPVNODECORE
+#define KAVLKEY AVLPVKEY
+#define PKAVLKEY PAVLPVKEY
+#define KAVLENUMDATA AVLPVENUMDATA
+#define PKAVLENUMDATA PAVLPVENUMDATA
+#define PKAVLCALLBACK PAVLPVCALLBACK
+
+
+/*
+ * AVL Compare macros
+ */
+#define KAVL_G(key1, key2) ( (const char*)(key1) > (const char*)(key2) )
+#define KAVL_E(key1, key2) ( (const char*)(key1) == (const char*)(key2) )
+#define KAVL_NE(key1, key2) ( (const char*)(key1) != (const char*)(key2) )
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/avl.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+
+/*
+ * Include the code.
+ */
+#define SSToDS(ptr) ptr
+#define KMAX RT_MAX
+#define kASSERT Assert
+#include "avl_Base.cpp.h"
+#include "avl_Get.cpp.h"
+#include "avl_GetBestFit.cpp.h"
+#include "avl_RemoveBestFit.cpp.h"
+#include "avl_DoWithAll.cpp.h"
+#include "avl_Destroy.cpp.h"
+
--- /dev/null
+/* $Id: time.cpp $ */
+/** @file
+ * IPRT - Time.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP RTLOGGROUP_TIME
+#include <iprt/time.h>
+#include "internal/iprt.h"
+
+#include <iprt/ctype.h>
+#include <iprt/string.h>
+#include <iprt/assert.h>
+#include "internal/time.h"
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/** The max year we possibly could implode. */
+#define RTTIME_MAX_YEAR (292 + 1970)
+/** The min year we possibly could implode. */
+#define RTTIME_MIN_YEAR (-293 + 1970)
+
+/** The max day supported by our time representation. (2262-04-11T23-47-16.854775807) */
+#define RTTIME_MAX_DAY (365*292+71 + 101-1)
+/** The min day supported by our time representation. (1677-09-21T00-12-43.145224192) */
+#define RTTIME_MIN_DAY (365*-293-70 + 264-1)
+
+/** The max nano second into the max day. (2262-04-11T23-47-16.854775807) */
+#define RTTIME_MAX_DAY_NANO ( INT64_C(1000000000) * (23*3600 + 47*60 + 16) + 854775807 )
+/** The min nano second into the min day. (1677-09-21T00-12-43.145224192) */
+#define RTTIME_MIN_DAY_NANO ( INT64_C(1000000000) * (00*3600 + 12*60 + 43) + 145224192 )
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/**
+ * Days per month in a common year.
+ */
+static const uint8_t g_acDaysInMonths[12] =
+{
+ /*Jan Feb Mar Arp May Jun Jul Aug Sep Oct Nov Dec */
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+/**
+ * Days per month in a leap year.
+ */
+static const uint8_t g_acDaysInMonthsLeap[12] =
+{
+ /*Jan Feb Mar Arp May Jun Jul Aug Sep Oct Nov Dec */
+ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+/**
+ * The day of year for each month in a common year.
+ */
+static const uint16_t g_aiDayOfYear[12 + 1] =
+{
+ 1, /* Jan */
+ 1+31, /* Feb */
+ 1+31+28, /* Mar */
+ 1+31+28+31, /* Apr */
+ 1+31+28+31+30, /* May */
+ 1+31+28+31+30+31, /* Jun */
+ 1+31+28+31+30+31+30, /* Jul */
+ 1+31+28+31+30+31+30+31, /* Aug */
+ 1+31+28+31+30+31+30+31+31, /* Sep */
+ 1+31+28+31+30+31+30+31+31+30, /* Oct */
+ 1+31+28+31+30+31+30+31+31+30+31, /* Nov */
+ 1+31+28+31+30+31+30+31+31+30+31+30, /* Dec */
+ 1+31+28+31+30+31+30+31+31+30+31+30+31
+};
+
+/**
+ * The day of year for each month in a leap year.
+ */
+static const uint16_t g_aiDayOfYearLeap[12 + 1] =
+{
+ 1, /* Jan */
+ 1+31, /* Feb */
+ 1+31+29, /* Mar */
+ 1+31+29+31, /* Apr */
+ 1+31+29+31+30, /* May */
+ 1+31+29+31+30+31, /* Jun */
+ 1+31+29+31+30+31+30, /* Jul */
+ 1+31+29+31+30+31+30+31, /* Aug */
+ 1+31+29+31+30+31+30+31+31, /* Sep */
+ 1+31+29+31+30+31+30+31+31+30, /* Oct */
+ 1+31+29+31+30+31+30+31+31+30+31, /* Nov */
+ 1+31+29+31+30+31+30+31+31+30+31+30, /* Dec */
+ 1+31+29+31+30+31+30+31+31+30+31+30+31
+};
+
+/** The index of 1970 in g_aoffYear */
+#define OFF_YEAR_IDX_EPOCH 300
+/** The year of the first index. */
+#define OFF_YEAR_IDX_0_YEAR 1670
+
+/**
+ * The number of days the 1st of January a year is offseted from 1970-01-01.
+ */
+static const int32_t g_aoffYear[] =
+{
+/*1670:*/ 365*-300+-72, 365*-299+-72, 365*-298+-72, 365*-297+-71, 365*-296+-71, 365*-295+-71, 365*-294+-71, 365*-293+-70, 365*-292+-70, 365*-291+-70,
+/*1680:*/ 365*-290+-70, 365*-289+-69, 365*-288+-69, 365*-287+-69, 365*-286+-69, 365*-285+-68, 365*-284+-68, 365*-283+-68, 365*-282+-68, 365*-281+-67,
+/*1690:*/ 365*-280+-67, 365*-279+-67, 365*-278+-67, 365*-277+-66, 365*-276+-66, 365*-275+-66, 365*-274+-66, 365*-273+-65, 365*-272+-65, 365*-271+-65,
+/*1700:*/ 365*-270+-65, 365*-269+-65, 365*-268+-65, 365*-267+-65, 365*-266+-65, 365*-265+-64, 365*-264+-64, 365*-263+-64, 365*-262+-64, 365*-261+-63,
+/*1710:*/ 365*-260+-63, 365*-259+-63, 365*-258+-63, 365*-257+-62, 365*-256+-62, 365*-255+-62, 365*-254+-62, 365*-253+-61, 365*-252+-61, 365*-251+-61,
+/*1720:*/ 365*-250+-61, 365*-249+-60, 365*-248+-60, 365*-247+-60, 365*-246+-60, 365*-245+-59, 365*-244+-59, 365*-243+-59, 365*-242+-59, 365*-241+-58,
+/*1730:*/ 365*-240+-58, 365*-239+-58, 365*-238+-58, 365*-237+-57, 365*-236+-57, 365*-235+-57, 365*-234+-57, 365*-233+-56, 365*-232+-56, 365*-231+-56,
+/*1740:*/ 365*-230+-56, 365*-229+-55, 365*-228+-55, 365*-227+-55, 365*-226+-55, 365*-225+-54, 365*-224+-54, 365*-223+-54, 365*-222+-54, 365*-221+-53,
+/*1750:*/ 365*-220+-53, 365*-219+-53, 365*-218+-53, 365*-217+-52, 365*-216+-52, 365*-215+-52, 365*-214+-52, 365*-213+-51, 365*-212+-51, 365*-211+-51,
+/*1760:*/ 365*-210+-51, 365*-209+-50, 365*-208+-50, 365*-207+-50, 365*-206+-50, 365*-205+-49, 365*-204+-49, 365*-203+-49, 365*-202+-49, 365*-201+-48,
+/*1770:*/ 365*-200+-48, 365*-199+-48, 365*-198+-48, 365*-197+-47, 365*-196+-47, 365*-195+-47, 365*-194+-47, 365*-193+-46, 365*-192+-46, 365*-191+-46,
+/*1780:*/ 365*-190+-46, 365*-189+-45, 365*-188+-45, 365*-187+-45, 365*-186+-45, 365*-185+-44, 365*-184+-44, 365*-183+-44, 365*-182+-44, 365*-181+-43,
+/*1790:*/ 365*-180+-43, 365*-179+-43, 365*-178+-43, 365*-177+-42, 365*-176+-42, 365*-175+-42, 365*-174+-42, 365*-173+-41, 365*-172+-41, 365*-171+-41,
+/*1800:*/ 365*-170+-41, 365*-169+-41, 365*-168+-41, 365*-167+-41, 365*-166+-41, 365*-165+-40, 365*-164+-40, 365*-163+-40, 365*-162+-40, 365*-161+-39,
+/*1810:*/ 365*-160+-39, 365*-159+-39, 365*-158+-39, 365*-157+-38, 365*-156+-38, 365*-155+-38, 365*-154+-38, 365*-153+-37, 365*-152+-37, 365*-151+-37,
+/*1820:*/ 365*-150+-37, 365*-149+-36, 365*-148+-36, 365*-147+-36, 365*-146+-36, 365*-145+-35, 365*-144+-35, 365*-143+-35, 365*-142+-35, 365*-141+-34,
+/*1830:*/ 365*-140+-34, 365*-139+-34, 365*-138+-34, 365*-137+-33, 365*-136+-33, 365*-135+-33, 365*-134+-33, 365*-133+-32, 365*-132+-32, 365*-131+-32,
+/*1840:*/ 365*-130+-32, 365*-129+-31, 365*-128+-31, 365*-127+-31, 365*-126+-31, 365*-125+-30, 365*-124+-30, 365*-123+-30, 365*-122+-30, 365*-121+-29,
+/*1850:*/ 365*-120+-29, 365*-119+-29, 365*-118+-29, 365*-117+-28, 365*-116+-28, 365*-115+-28, 365*-114+-28, 365*-113+-27, 365*-112+-27, 365*-111+-27,
+/*1860:*/ 365*-110+-27, 365*-109+-26, 365*-108+-26, 365*-107+-26, 365*-106+-26, 365*-105+-25, 365*-104+-25, 365*-103+-25, 365*-102+-25, 365*-101+-24,
+/*1870:*/ 365*-100+-24, 365* -99+-24, 365* -98+-24, 365* -97+-23, 365* -96+-23, 365* -95+-23, 365* -94+-23, 365* -93+-22, 365* -92+-22, 365* -91+-22,
+/*1880:*/ 365* -90+-22, 365* -89+-21, 365* -88+-21, 365* -87+-21, 365* -86+-21, 365* -85+-20, 365* -84+-20, 365* -83+-20, 365* -82+-20, 365* -81+-19,
+/*1890:*/ 365* -80+-19, 365* -79+-19, 365* -78+-19, 365* -77+-18, 365* -76+-18, 365* -75+-18, 365* -74+-18, 365* -73+-17, 365* -72+-17, 365* -71+-17,
+/*1900:*/ 365* -70+-17, 365* -69+-17, 365* -68+-17, 365* -67+-17, 365* -66+-17, 365* -65+-16, 365* -64+-16, 365* -63+-16, 365* -62+-16, 365* -61+-15,
+/*1910:*/ 365* -60+-15, 365* -59+-15, 365* -58+-15, 365* -57+-14, 365* -56+-14, 365* -55+-14, 365* -54+-14, 365* -53+-13, 365* -52+-13, 365* -51+-13,
+/*1920:*/ 365* -50+-13, 365* -49+-12, 365* -48+-12, 365* -47+-12, 365* -46+-12, 365* -45+-11, 365* -44+-11, 365* -43+-11, 365* -42+-11, 365* -41+-10,
+/*1930:*/ 365* -40+-10, 365* -39+-10, 365* -38+-10, 365* -37+-9 , 365* -36+-9 , 365* -35+-9 , 365* -34+-9 , 365* -33+-8 , 365* -32+-8 , 365* -31+-8 ,
+/*1940:*/ 365* -30+-8 , 365* -29+-7 , 365* -28+-7 , 365* -27+-7 , 365* -26+-7 , 365* -25+-6 , 365* -24+-6 , 365* -23+-6 , 365* -22+-6 , 365* -21+-5 ,
+/*1950:*/ 365* -20+-5 , 365* -19+-5 , 365* -18+-5 , 365* -17+-4 , 365* -16+-4 , 365* -15+-4 , 365* -14+-4 , 365* -13+-3 , 365* -12+-3 , 365* -11+-3 ,
+/*1960:*/ 365* -10+-3 , 365* -9+-2 , 365* -8+-2 , 365* -7+-2 , 365* -6+-2 , 365* -5+-1 , 365* -4+-1 , 365* -3+-1 , 365* -2+-1 , 365* -1+0 ,
+/*1970:*/ 365* 0+0 , 365* 1+0 , 365* 2+0 , 365* 3+1 , 365* 4+1 , 365* 5+1 , 365* 6+1 , 365* 7+2 , 365* 8+2 , 365* 9+2 ,
+/*1980:*/ 365* 10+2 , 365* 11+3 , 365* 12+3 , 365* 13+3 , 365* 14+3 , 365* 15+4 , 365* 16+4 , 365* 17+4 , 365* 18+4 , 365* 19+5 ,
+/*1990:*/ 365* 20+5 , 365* 21+5 , 365* 22+5 , 365* 23+6 , 365* 24+6 , 365* 25+6 , 365* 26+6 , 365* 27+7 , 365* 28+7 , 365* 29+7 ,
+/*2000:*/ 365* 30+7 , 365* 31+8 , 365* 32+8 , 365* 33+8 , 365* 34+8 , 365* 35+9 , 365* 36+9 , 365* 37+9 , 365* 38+9 , 365* 39+10 ,
+/*2010:*/ 365* 40+10 , 365* 41+10 , 365* 42+10 , 365* 43+11 , 365* 44+11 , 365* 45+11 , 365* 46+11 , 365* 47+12 , 365* 48+12 , 365* 49+12 ,
+/*2020:*/ 365* 50+12 , 365* 51+13 , 365* 52+13 , 365* 53+13 , 365* 54+13 , 365* 55+14 , 365* 56+14 , 365* 57+14 , 365* 58+14 , 365* 59+15 ,
+/*2030:*/ 365* 60+15 , 365* 61+15 , 365* 62+15 , 365* 63+16 , 365* 64+16 , 365* 65+16 , 365* 66+16 , 365* 67+17 , 365* 68+17 , 365* 69+17 ,
+/*2040:*/ 365* 70+17 , 365* 71+18 , 365* 72+18 , 365* 73+18 , 365* 74+18 , 365* 75+19 , 365* 76+19 , 365* 77+19 , 365* 78+19 , 365* 79+20 ,
+/*2050:*/ 365* 80+20 , 365* 81+20 , 365* 82+20 , 365* 83+21 , 365* 84+21 , 365* 85+21 , 365* 86+21 , 365* 87+22 , 365* 88+22 , 365* 89+22 ,
+/*2060:*/ 365* 90+22 , 365* 91+23 , 365* 92+23 , 365* 93+23 , 365* 94+23 , 365* 95+24 , 365* 96+24 , 365* 97+24 , 365* 98+24 , 365* 99+25 ,
+/*2070:*/ 365* 100+25 , 365* 101+25 , 365* 102+25 , 365* 103+26 , 365* 104+26 , 365* 105+26 , 365* 106+26 , 365* 107+27 , 365* 108+27 , 365* 109+27 ,
+/*2080:*/ 365* 110+27 , 365* 111+28 , 365* 112+28 , 365* 113+28 , 365* 114+28 , 365* 115+29 , 365* 116+29 , 365* 117+29 , 365* 118+29 , 365* 119+30 ,
+/*2090:*/ 365* 120+30 , 365* 121+30 , 365* 122+30 , 365* 123+31 , 365* 124+31 , 365* 125+31 , 365* 126+31 , 365* 127+32 , 365* 128+32 , 365* 129+32 ,
+/*2100:*/ 365* 130+32 , 365* 131+32 , 365* 132+32 , 365* 133+32 , 365* 134+32 , 365* 135+33 , 365* 136+33 , 365* 137+33 , 365* 138+33 , 365* 139+34 ,
+/*2110:*/ 365* 140+34 , 365* 141+34 , 365* 142+34 , 365* 143+35 , 365* 144+35 , 365* 145+35 , 365* 146+35 , 365* 147+36 , 365* 148+36 , 365* 149+36 ,
+/*2120:*/ 365* 150+36 , 365* 151+37 , 365* 152+37 , 365* 153+37 , 365* 154+37 , 365* 155+38 , 365* 156+38 , 365* 157+38 , 365* 158+38 , 365* 159+39 ,
+/*2130:*/ 365* 160+39 , 365* 161+39 , 365* 162+39 , 365* 163+40 , 365* 164+40 , 365* 165+40 , 365* 166+40 , 365* 167+41 , 365* 168+41 , 365* 169+41 ,
+/*2140:*/ 365* 170+41 , 365* 171+42 , 365* 172+42 , 365* 173+42 , 365* 174+42 , 365* 175+43 , 365* 176+43 , 365* 177+43 , 365* 178+43 , 365* 179+44 ,
+/*2150:*/ 365* 180+44 , 365* 181+44 , 365* 182+44 , 365* 183+45 , 365* 184+45 , 365* 185+45 , 365* 186+45 , 365* 187+46 , 365* 188+46 , 365* 189+46 ,
+/*2160:*/ 365* 190+46 , 365* 191+47 , 365* 192+47 , 365* 193+47 , 365* 194+47 , 365* 195+48 , 365* 196+48 , 365* 197+48 , 365* 198+48 , 365* 199+49 ,
+/*2170:*/ 365* 200+49 , 365* 201+49 , 365* 202+49 , 365* 203+50 , 365* 204+50 , 365* 205+50 , 365* 206+50 , 365* 207+51 , 365* 208+51 , 365* 209+51 ,
+/*2180:*/ 365* 210+51 , 365* 211+52 , 365* 212+52 , 365* 213+52 , 365* 214+52 , 365* 215+53 , 365* 216+53 , 365* 217+53 , 365* 218+53 , 365* 219+54 ,
+/*2190:*/ 365* 220+54 , 365* 221+54 , 365* 222+54 , 365* 223+55 , 365* 224+55 , 365* 225+55 , 365* 226+55 , 365* 227+56 , 365* 228+56 , 365* 229+56 ,
+/*2200:*/ 365* 230+56 , 365* 231+56 , 365* 232+56 , 365* 233+56 , 365* 234+56 , 365* 235+57 , 365* 236+57 , 365* 237+57 , 365* 238+57 , 365* 239+58 ,
+/*2210:*/ 365* 240+58 , 365* 241+58 , 365* 242+58 , 365* 243+59 , 365* 244+59 , 365* 245+59 , 365* 246+59 , 365* 247+60 , 365* 248+60 , 365* 249+60 ,
+/*2220:*/ 365* 250+60 , 365* 251+61 , 365* 252+61 , 365* 253+61 , 365* 254+61 , 365* 255+62 , 365* 256+62 , 365* 257+62 , 365* 258+62 , 365* 259+63 ,
+/*2230:*/ 365* 260+63 , 365* 261+63 , 365* 262+63 , 365* 263+64 , 365* 264+64 , 365* 265+64 , 365* 266+64 , 365* 267+65 , 365* 268+65 , 365* 269+65 ,
+/*2240:*/ 365* 270+65 , 365* 271+66 , 365* 272+66 , 365* 273+66 , 365* 274+66 , 365* 275+67 , 365* 276+67 , 365* 277+67 , 365* 278+67 , 365* 279+68 ,
+/*2250:*/ 365* 280+68 , 365* 281+68 , 365* 282+68 , 365* 283+69 , 365* 284+69 , 365* 285+69 , 365* 286+69 , 365* 287+70 , 365* 288+70 , 365* 289+70 ,
+/*2260:*/ 365* 290+70 , 365* 291+71 , 365* 292+71 , 365* 293+71 , 365* 294+71 , 365* 295+72 , 365* 296+72 , 365* 297+72 , 365* 298+72 , 365* 299+73
+};
+
+/* generator code:
+#include <stdio.h>
+bool isLeapYear(int iYear)
+{
+ return iYear % 4 == 0 && (iYear % 100 != 0 || iYear % 400 == 0);
+}
+void printYear(int iYear, int iLeap)
+{
+ if (!(iYear % 10))
+ printf("\n/" "*%d:*" "/", iYear + 1970);
+ printf(" 365*%4d+%-3d,", iYear, iLeap);
+}
+int main()
+{
+ int iYear = 0;
+ int iLeap = 0;
+ while (iYear > -300)
+ iLeap -= isLeapYear(1970 + --iYear);
+ while (iYear < 300)
+ {
+ printYear(iYear, iLeap);
+ iLeap += isLeapYear(1970 + iYear++);
+ }
+ printf("\n");
+ return 0;
+}
+*/
+
+
+/**
+ * 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.
+ */
+DECLINLINE(bool) rtTimeIsLeapYear(int32_t i32Year)
+{
+ return i32Year % 4 == 0
+ && ( i32Year % 100 != 0
+ || i32Year % 400 == 0);
+}
+
+
+/**
+ * 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)
+{
+ return rtTimeIsLeapYear(i32Year);
+}
+RT_EXPORT_SYMBOL(RTTimeIsLeapYear);
+
+
+/**
+ * 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)
+{
+ int64_t i64Div;
+ int32_t i32Div;
+ int32_t i32Rem;
+ unsigned iYear;
+ const uint16_t *paiDayOfYear;
+ int iMonth;
+
+ AssertMsg(VALID_PTR(pTime), ("%p\n", pTime));
+ AssertMsg(VALID_PTR(pTimeSpec), ("%p\n", pTime));
+
+ /*
+ * The simple stuff first.
+ */
+ pTime->fFlags = RTTIME_FLAGS_TYPE_UTC;
+ i64Div = pTimeSpec->i64NanosecondsRelativeToUnixEpoch;
+ i32Rem = (int32_t)(i64Div % 1000000000);
+ i64Div /= 1000000000;
+ if (i32Rem < 0)
+ {
+ i32Rem += 1000000000;
+ i64Div--;
+ }
+ pTime->u32Nanosecond = i32Rem;
+
+ /* second */
+ i32Rem = (int32_t)(i64Div % 60);
+ i64Div /= 60;
+ if (i32Rem < 0)
+ {
+ i32Rem += 60;
+ i64Div--;
+ }
+ pTime->u8Second = i32Rem;
+
+ /* minute */
+ i32Div = (int32_t)i64Div; /* 60,000,000,000 > 33bit, so 31bit suffices. */
+ i32Rem = i32Div % 60;
+ i32Div /= 60;
+ if (i32Rem < 0)
+ {
+ i32Rem += 60;
+ i32Div--;
+ }
+ pTime->u8Minute = i32Rem;
+
+ /* hour */
+ i32Rem = i32Div % 24;
+ i32Div /= 24; /* days relative to 1970-01-01 */
+ if (i32Rem < 0)
+ {
+ i32Rem += 24;
+ i32Div--;
+ }
+ pTime->u8Hour = i32Rem;
+
+ /* weekday - 1970-01-01 was a Thursday (3) */
+ pTime->u8WeekDay = ((int)(i32Div % 7) + 3 + 7) % 7;
+
+ /*
+ * We've now got a number of days relative to 1970-01-01.
+ * To get the correct year number we have to mess with leap years. Fortunately,
+ * the representation we've got only supports a few hundred years, so we can
+ * generate a table and perform a simple two way search from the modulus 365 derived.
+ */
+ iYear = OFF_YEAR_IDX_EPOCH + i32Div / 365;
+ while (g_aoffYear[iYear + 1] <= i32Div)
+ iYear++;
+ while (g_aoffYear[iYear] > i32Div)
+ iYear--;
+ pTime->i32Year = iYear + OFF_YEAR_IDX_0_YEAR;
+ i32Div -= g_aoffYear[iYear];
+ pTime->u16YearDay = i32Div + 1;
+
+ /*
+ * Figuring out the month is done in a manner similar to the year, only here we
+ * ensure that the index is matching or too small.
+ */
+ if (rtTimeIsLeapYear(pTime->i32Year))
+ {
+ pTime->fFlags |= RTTIME_FLAGS_LEAP_YEAR;
+ paiDayOfYear = &g_aiDayOfYearLeap[0];
+ }
+ else
+ {
+ pTime->fFlags |= RTTIME_FLAGS_COMMON_YEAR;
+ paiDayOfYear = &g_aiDayOfYear[0];
+ }
+ iMonth = i32Div / 32;
+ i32Div++;
+ while (paiDayOfYear[iMonth + 1] <= i32Div)
+ iMonth++;
+ pTime->u8Month = iMonth + 1;
+ i32Div -= paiDayOfYear[iMonth];
+ pTime->u8MonthDay = i32Div + 1;
+
+ /* This is for UTC timespecs, so, no offset. */
+ pTime->offUTC = 0;
+
+ return pTime;
+}
+RT_EXPORT_SYMBOL(RTTimeExplode);
+
+
+/**
+ * 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)
+{
+ int32_t i32Days;
+ uint32_t u32Secs;
+ int64_t i64Nanos;
+
+ /*
+ * Validate input.
+ */
+ AssertReturn(VALID_PTR(pTimeSpec), NULL);
+ AssertReturn(VALID_PTR(pTime), NULL);
+ AssertReturn(pTime->u32Nanosecond < 1000000000, NULL);
+ AssertReturn(pTime->u8Second < 60, NULL);
+ AssertReturn(pTime->u8Minute < 60, NULL);
+ AssertReturn(pTime->u8Hour < 24, NULL);
+ AssertReturn(pTime->u16YearDay >= 1, NULL);
+ AssertReturn(pTime->u16YearDay <= (rtTimeIsLeapYear(pTime->i32Year) ? 366 : 365), NULL);
+ AssertMsgReturn(pTime->i32Year <= RTTIME_MAX_YEAR && pTime->i32Year >= RTTIME_MIN_YEAR, ("%RI32\n", pTime->i32Year), NULL);
+
+ /*
+ * Do the conversion to nanoseconds.
+ */
+ i32Days = g_aoffYear[pTime->i32Year - OFF_YEAR_IDX_0_YEAR]
+ + pTime->u16YearDay - 1;
+ AssertMsgReturn(i32Days <= RTTIME_MAX_DAY && i32Days >= RTTIME_MIN_DAY, ("%RI32\n", i32Days), NULL);
+
+ u32Secs = pTime->u8Second
+ + pTime->u8Minute * 60
+ + pTime->u8Hour * 3600;
+ i64Nanos = (uint64_t)pTime->u32Nanosecond
+ + u32Secs * UINT64_C(1000000000);
+ AssertMsgReturn(i32Days != RTTIME_MAX_DAY || i64Nanos <= RTTIME_MAX_DAY_NANO, ("%RI64\n", i64Nanos), NULL);
+ AssertMsgReturn(i32Days != RTTIME_MIN_DAY || i64Nanos >= RTTIME_MIN_DAY_NANO, ("%RI64\n", i64Nanos), NULL);
+
+ i64Nanos += i32Days * UINT64_C(86400000000000);
+
+ pTimeSpec->i64NanosecondsRelativeToUnixEpoch = i64Nanos;
+ return pTimeSpec;
+}
+RT_EXPORT_SYMBOL(RTTimeImplode);
+
+
+/**
+ * Internal worker for RTTimeNormalize and RTTimeLocalNormalize.
+ * It doesn't adjust the UCT offset but leaves that for RTTimeLocalNormalize.
+ */
+static PRTTIME rtTimeNormalizeInternal(PRTTIME pTime)
+{
+ unsigned uSecond;
+ unsigned uMinute;
+ unsigned uHour;
+ bool fLeapYear;
+
+ /*
+ * Fix the YearDay and Month/MonthDay.
+ */
+ fLeapYear = rtTimeIsLeapYear(pTime->i32Year);
+ if (!pTime->u16YearDay)
+ {
+ /*
+ * The Month+MonthDay must present, overflow adjust them and calc the year day.
+ */
+ AssertMsgReturn( pTime->u8Month
+ && pTime->u8MonthDay,
+ ("date=%d-%d-%d\n", pTime->i32Year, pTime->u8Month, pTime->u8MonthDay),
+ NULL);
+ while (pTime->u8Month > 12)
+ {
+ pTime->u8Month -= 12;
+ pTime->i32Year++;
+ fLeapYear = rtTimeIsLeapYear(pTime->i32Year);
+ pTime->fFlags &= ~(RTTIME_FLAGS_COMMON_YEAR | RTTIME_FLAGS_LEAP_YEAR);
+ }
+
+ for (;;)
+ {
+ unsigned cDaysInMonth = fLeapYear
+ ? g_acDaysInMonthsLeap[pTime->u8Month - 1]
+ : g_acDaysInMonths[pTime->u8Month - 1];
+ if (pTime->u8MonthDay <= cDaysInMonth)
+ break;
+ pTime->u8MonthDay -= cDaysInMonth;
+ if (pTime->u8Month != 12)
+ pTime->u8Month++;
+ else
+ {
+ pTime->u8Month = 1;
+ pTime->i32Year++;
+ fLeapYear = rtTimeIsLeapYear(pTime->i32Year);
+ pTime->fFlags &= ~(RTTIME_FLAGS_COMMON_YEAR | RTTIME_FLAGS_LEAP_YEAR);
+ }
+ }
+
+ pTime->u16YearDay = pTime->u8MonthDay - 1
+ + (fLeapYear
+ ? g_aiDayOfYearLeap[pTime->u8Month - 1]
+ : g_aiDayOfYear[pTime->u8Month - 1]);
+ }
+ else
+ {
+ /*
+ * Are both YearDay and Month/MonthDay valid?
+ * Check that they don't overflow and match, if not use YearDay (simpler).
+ */
+ bool fRecalc = true;
+ if ( pTime->u8Month
+ && pTime->u8MonthDay)
+ {
+ do
+ {
+ uint16_t u16YearDay;
+
+ /* If you change one, zero the other to make clear what you mean. */
+ AssertBreak(pTime->u8Month <= 12);
+ AssertBreak(pTime->u8MonthDay <= (fLeapYear
+ ? g_acDaysInMonthsLeap[pTime->u8Month - 1]
+ : g_acDaysInMonths[pTime->u8Month - 1]));
+ u16YearDay = pTime->u8MonthDay - 1
+ + (fLeapYear
+ ? g_aiDayOfYearLeap[pTime->u8Month - 1]
+ : g_aiDayOfYear[pTime->u8Month - 1]);
+ AssertBreak(u16YearDay == pTime->u16YearDay);
+ fRecalc = false;
+ } while (0);
+ }
+ if (fRecalc)
+ {
+ const uint16_t *paiDayOfYear;
+
+ /* overflow adjust YearDay */
+ while (pTime->u16YearDay > (fLeapYear ? 366 : 365))
+ {
+ pTime->u16YearDay -= fLeapYear ? 366 : 365;
+ pTime->i32Year++;
+ fLeapYear = rtTimeIsLeapYear(pTime->i32Year);
+ pTime->fFlags &= ~(RTTIME_FLAGS_COMMON_YEAR | RTTIME_FLAGS_LEAP_YEAR);
+ }
+
+ /* calc Month and MonthDay */
+ paiDayOfYear = fLeapYear
+ ? &g_aiDayOfYearLeap[0]
+ : &g_aiDayOfYear[0];
+ pTime->u8Month = 1;
+ while (pTime->u16YearDay > paiDayOfYear[pTime->u8Month])
+ pTime->u8Month++;
+ Assert(pTime->u8Month >= 1 && pTime->u8Month <= 12);
+ pTime->u8MonthDay = pTime->u16YearDay - paiDayOfYear[pTime->u8Month - 1] + 1;
+ }
+ }
+
+ /*
+ * Fixup time overflows.
+ * Use unsigned int values internally to avoid overflows.
+ */
+ uSecond = pTime->u8Second;
+ uMinute = pTime->u8Minute;
+ uHour = pTime->u8Hour;
+
+ while (pTime->u32Nanosecond >= 1000000000)
+ {
+ pTime->u32Nanosecond -= 1000000000;
+ uSecond++;
+ }
+
+ while (uSecond >= 60)
+ {
+ uSecond -= 60;
+ uMinute++;
+ }
+
+ while (uMinute >= 60)
+ {
+ uMinute -= 60;
+ uHour++;
+ }
+
+ while (uHour >= 24)
+ {
+ uHour -= 24;
+
+ /* This is really a RTTimeIncDay kind of thing... */
+ if (pTime->u16YearDay + 1 != (fLeapYear ? g_aiDayOfYearLeap[pTime->u8Month] : g_aiDayOfYear[pTime->u8Month]))
+ {
+ pTime->u16YearDay++;
+ pTime->u8MonthDay++;
+ }
+ else if (pTime->u8Month != 12)
+ {
+ pTime->u16YearDay++;
+ pTime->u8Month++;
+ pTime->u8MonthDay = 1;
+ }
+ else
+ {
+ pTime->i32Year++;
+ fLeapYear = rtTimeIsLeapYear(pTime->i32Year);
+ pTime->fFlags &= ~(RTTIME_FLAGS_COMMON_YEAR | RTTIME_FLAGS_LEAP_YEAR);
+ pTime->u16YearDay = 1;
+ pTime->u8Month = 1;
+ pTime->u8MonthDay = 1;
+ }
+ }
+
+ pTime->u8Second = uSecond;
+ pTime->u8Minute = uMinute;
+ pTime->u8Hour = uHour;
+
+ /*
+ * Correct the leap year flag.
+ * Assert if it's wrong, but ignore if unset.
+ */
+ if (fLeapYear)
+ {
+ Assert(!(pTime->fFlags & RTTIME_FLAGS_COMMON_YEAR));
+ pTime->fFlags &= ~RTTIME_FLAGS_COMMON_YEAR;
+ pTime->fFlags |= RTTIME_FLAGS_LEAP_YEAR;
+ }
+ else
+ {
+ Assert(!(pTime->fFlags & RTTIME_FLAGS_LEAP_YEAR));
+ pTime->fFlags &= ~RTTIME_FLAGS_LEAP_YEAR;
+ pTime->fFlags |= RTTIME_FLAGS_COMMON_YEAR;
+ }
+
+
+ /*
+ * Calc week day.
+ *
+ * 1970-01-01 was a Thursday (3), so find the number of days relative to
+ * that point. We use the table when possible and a slow+stupid+brute-force
+ * algorithm for points outside it. Feel free to optimize the latter by
+ * using some clever formula.
+ */
+ if ( pTime->i32Year >= OFF_YEAR_IDX_0_YEAR
+ && pTime->i32Year < OFF_YEAR_IDX_0_YEAR + (int32_t)RT_ELEMENTS(g_aoffYear))
+ {
+ int32_t offDays = g_aoffYear[pTime->i32Year - OFF_YEAR_IDX_0_YEAR]
+ + pTime->u16YearDay -1;
+ pTime->u8WeekDay = ((offDays % 7) + 3 + 7) % 7;
+ }
+ else
+ {
+ int32_t i32Year = pTime->i32Year;
+ if (i32Year >= 1970)
+ {
+ uint64_t offDays = pTime->u16YearDay - 1;
+ while (--i32Year >= 1970)
+ offDays += rtTimeIsLeapYear(i32Year) ? 366 : 365;
+ pTime->u8WeekDay = (uint8_t)((offDays + 3) % 7);
+ }
+ else
+ {
+ int64_t offDays = (fLeapYear ? -366 - 1 : -365 - 1) + pTime->u16YearDay;
+ while (++i32Year < 1970)
+ offDays -= rtTimeIsLeapYear(i32Year) ? 366 : 365;
+ pTime->u8WeekDay = ((int)(offDays % 7) + 3 + 7) % 7;
+ }
+ }
+ return 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 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)
+{
+ /*
+ * Validate that we've got the minimum of stuff handy.
+ */
+ AssertReturn(VALID_PTR(pTime), NULL);
+ AssertMsgReturn(!(pTime->fFlags & ~RTTIME_FLAGS_MASK), ("%#x\n", pTime->fFlags), NULL);
+ AssertMsgReturn((pTime->fFlags & RTTIME_FLAGS_TYPE_MASK) != RTTIME_FLAGS_TYPE_LOCAL, ("Use RTTimeLocalNormalize!\n"), NULL);
+ AssertMsgReturn(pTime->offUTC == 0, ("%d; Use RTTimeLocalNormalize!\n", pTime->offUTC), NULL);
+
+ pTime = rtTimeNormalizeInternal(pTime);
+ if (pTime)
+ pTime->fFlags |= RTTIME_FLAGS_TYPE_UTC;
+ return pTime;
+}
+RT_EXPORT_SYMBOL(RTTimeNormalize);
+
+
+/**
+ * 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)
+{
+ size_t cch;
+
+ /* (Default to UTC if not specified) */
+ if ( (pTime->fFlags & RTTIME_FLAGS_TYPE_MASK) == RTTIME_FLAGS_TYPE_LOCAL
+ && pTime->offUTC)
+ {
+ int32_t offUTCHour = pTime->offUTC / 60;
+ int32_t offUTCMinute = pTime->offUTC % 60;
+ char chSign;
+ Assert(pTime->offUTC <= 840 && pTime->offUTC >= -840);
+ if (pTime->offUTC >= 0)
+ chSign = '+';
+ else
+ {
+ chSign = '-';
+ offUTCMinute = -offUTCMinute;
+ offUTCHour = -offUTCHour;
+ }
+ cch = RTStrPrintf(psz, cb,
+ "%RI32-%02u-%02uT%02u:%02u:%02u.%09RU32%c%02d%02d",
+ pTime->i32Year, pTime->u8Month, pTime->u8MonthDay,
+ pTime->u8Hour, pTime->u8Minute, pTime->u8Second, pTime->u32Nanosecond,
+ chSign, offUTCHour, offUTCMinute);
+ if ( cch <= 15
+ || psz[cch - 5] != chSign)
+ return NULL;
+ }
+ else
+ {
+ cch = RTStrPrintf(psz, cb, "%RI32-%02u-%02uT%02u:%02u:%02u.%09RU32Z",
+ pTime->i32Year, pTime->u8Month, pTime->u8MonthDay,
+ pTime->u8Hour, pTime->u8Minute, pTime->u8Second, pTime->u32Nanosecond);
+ if ( cch <= 15
+ || psz[cch - 1] != 'Z')
+ return NULL;
+ }
+ return psz;
+}
+RT_EXPORT_SYMBOL(RTTimeToString);
+
+
+/**
+ * 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)
+{
+ RTTIME Time;
+ return RTTimeToString(RTTimeExplode(&Time, pTime), psz, cb);
+}
+RT_EXPORT_SYMBOL(RTTimeSpecToString);
+
+
+
+/**
+ * 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)
+{
+ /* Ignore leading spaces. */
+ while (RT_C_IS_SPACE(*pszString))
+ pszString++;
+
+ /*
+ * Init non date & time parts.
+ */
+ pTime->fFlags = RTTIME_FLAGS_TYPE_LOCAL;
+ pTime->offUTC = 0;
+
+ /*
+ * The day part.
+ */
+
+ /* Year */
+ int rc = RTStrToInt32Ex(pszString, (char **)&pszString, 10, &pTime->i32Year);
+ if (rc != VWRN_TRAILING_CHARS)
+ return NULL;
+
+ bool const fLeapYear = rtTimeIsLeapYear(pTime->i32Year);
+ if (fLeapYear)
+ pTime->fFlags |= RTTIME_FLAGS_LEAP_YEAR;
+
+ if (*pszString++ != '-')
+ return NULL;
+
+ /* Month of the year. */
+ rc = RTStrToUInt8Ex(pszString, (char **)&pszString, 10, &pTime->u8Month);
+ if (rc != VWRN_TRAILING_CHARS)
+ return NULL;
+ if (pTime->u8Month == 0 || pTime->u8Month > 12)
+ return NULL;
+ if (*pszString++ != '-')
+ return NULL;
+
+ /* Day of month.*/
+ rc = RTStrToUInt8Ex(pszString, (char **)&pszString, 10, &pTime->u8MonthDay);
+ if (rc != VWRN_TRAILING_CHARS && rc != VINF_SUCCESS)
+ return NULL;
+ unsigned const cDaysInMonth = fLeapYear
+ ? g_acDaysInMonthsLeap[pTime->u8Month - 1]
+ : g_acDaysInMonths[pTime->u8Month - 1];
+ if (pTime->u8MonthDay == 0 || pTime->u8MonthDay > cDaysInMonth)
+ return NULL;
+
+ /* Calculate year day. */
+ pTime->u16YearDay = pTime->u8MonthDay - 1
+ + (fLeapYear
+ ? g_aiDayOfYearLeap[pTime->u8Month - 1]
+ : g_aiDayOfYear[pTime->u8Month - 1]);
+
+ /*
+ * The time part.
+ */
+ if (*pszString++ != 'T')
+ return NULL;
+
+ /* Hour. */
+ rc = RTStrToUInt8Ex(pszString, (char **)&pszString, 10, &pTime->u8Hour);
+ if (rc != VWRN_TRAILING_CHARS)
+ return NULL;
+ if (pTime->u8Hour > 23)
+ return NULL;
+ if (*pszString++ != ':')
+ return NULL;
+
+ /* Minute. */
+ rc = RTStrToUInt8Ex(pszString, (char **)&pszString, 10, &pTime->u8Minute);
+ if (rc != VWRN_TRAILING_CHARS)
+ return NULL;
+ if (pTime->u8Minute > 59)
+ return NULL;
+ if (*pszString++ != ':')
+ return NULL;
+
+ /* Second. */
+ rc = RTStrToUInt8Ex(pszString, (char **)&pszString, 10, &pTime->u8Minute);
+ if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS && rc != VWRN_TRAILING_SPACES)
+ return NULL;
+ if (pTime->u8Second > 59)
+ return NULL;
+
+ /* Nanoseconds is optional and probably non-standard. */
+ if (*pszString == '.')
+ {
+ rc = RTStrToUInt32Ex(pszString + 1, (char **)&pszString, 10, &pTime->u32Nanosecond);
+ if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS && rc != VWRN_TRAILING_SPACES)
+ return NULL;
+ if (pTime->u32Nanosecond >= 1000000000)
+ return NULL;
+ }
+ else
+ pTime->u32Nanosecond = 0;
+
+ /*
+ * Time zone.
+ */
+ if (*pszString == 'Z')
+ {
+ pszString++;
+ pTime->fFlags &= ~RTTIME_FLAGS_TYPE_MASK;
+ pTime->fFlags |= ~RTTIME_FLAGS_TYPE_UTC;
+ pTime->offUTC = 0;
+ }
+ else if ( *pszString == '+'
+ || *pszString == '-')
+ {
+ rc = RTStrToInt32Ex(pszString, (char **)&pszString, 10, &pTime->offUTC);
+ if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS && rc != VWRN_TRAILING_SPACES)
+ return NULL;
+ }
+ /* else: No time zone given, local with offUTC = 0. */
+
+ /*
+ * The rest of the string should be blanks.
+ */
+ char ch;
+ while ((ch = *pszString++) != '\0')
+ if (!RT_C_IS_BLANK(ch))
+ return NULL;
+
+ return pTime;
+}
+RT_EXPORT_SYMBOL(RTTimeFromString);
+
+
+/**
+ * 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)
+{
+ RTTIME Time;
+ if (RTTimeFromString(&Time, pszString))
+ return RTTimeImplode(pTime, &Time);
+ return NULL;
+}
+RT_EXPORT_SYMBOL(RTTimeSpecFromString);
+
--- /dev/null
+/* $Id: RTAssertShouldPanic-generic.cpp $ */
+/** @file
+ * IPRT - Assertions, generic RTAssertShouldPanic.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/assert.h>
+#include "internal/iprt.h"
+
+
+RTDECL(bool) RTAssertShouldPanic(void)
+{
+#if 0 /* Enable this to not panic on assertions. (Make sure this code is used!) */
+ return false;
+#else
+ return RTAssertMayPanic();
+#endif
+}
+RT_EXPORT_SYMBOL(RTAssertShouldPanic);
+
--- /dev/null
+/* $Id: RTLogWriteStdErr-stub-generic.cpp $ */
+/** @file
+ * IPRT - Log To StdErr, Generic Dummy.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/log.h>
+#include "internal/iprt.h"
+
+
+RTDECL(void) RTLogWriteStdErr(const char *pch, size_t cb)
+{
+ NOREF(pch);
+ NOREF(cb);
+ return;
+}
+RT_EXPORT_SYMBOL(RTLogWriteStdErr);
+
--- /dev/null
+/* $Id: RTLogWriteStdOut-stub-generic.cpp $ */
+/** @file
+ * IPRT - Log To StdOut, Generic Dummy.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/log.h>
+#include "internal/iprt.h"
+
+
+RTDECL(void) RTLogWriteStdOut(const char *pch, size_t cb)
+{
+ NOREF(pch);
+ NOREF(cb);
+ return;
+}
+RT_EXPORT_SYMBOL(RTLogWriteStdOut);
+
--- /dev/null
+/* $Id: RTMpGetCoreCount-generic.cpp $ */
+/** @file
+ * IPRT - Multiprocessor, Generic RTMpGetCoreCount.
+ */
+
+/*
+ * Copyright (C) 2013-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/mp.h>
+#include "internal/iprt.h"
+
+
+RTDECL(RTCPUID) RTMpGetCoreCount(void)
+{
+ return RTMpGetCount();
+}
+RT_EXPORT_SYMBOL(RTMpGetCoreCount);
+
--- /dev/null
+/* $Id: RTSemEventMultiWait-2-ex-generic.cpp $ */
+/** @file
+ * IPRT - RTSemEventMultiWait, implementation based on RTSemEventMultiWaitEx.
+ */
+
+/*
+ * Copyright (C) 2010-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP RTLOGGROUP_SEM
+#define RTSEMEVENTMULTI_WITHOUT_REMAPPING
+#include <iprt/semaphore.h>
+#include "internal/iprt.h"
+
+#include <iprt/err.h>
+#include <iprt/assert.h>
+
+
+RTDECL(int) RTSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies)
+{
+ int rc;
+ if (cMillies == RT_INDEFINITE_WAIT)
+ rc = RTSemEventMultiWaitEx(hEventMultiSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_INDEFINITE, 0);
+ else
+ rc = RTSemEventMultiWaitEx(hEventMultiSem,
+ RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_RELATIVE | RTSEMWAIT_FLAGS_MILLISECS,
+ cMillies);
+ Assert(rc != VERR_INTERRUPTED);
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTSemEventMultiWait);
+
--- /dev/null
+/* $Id: RTSemEventMultiWaitNoResume-2-ex-generic.cpp $ */
+/** @file
+ * IPRT - RTSemEventMultiWaitNoResume, generic implementation based
+ * on RTSemEventMultiWaitEx.
+ */
+
+/*
+ * Copyright (C) 2010-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP RTLOGGROUP_SEM
+#define RTSEMEVENTMULTI_WITHOUT_REMAPPING
+#include <iprt/semaphore.h>
+#include "internal/iprt.h"
+
+#include <iprt/err.h>
+#include <iprt/assert.h>
+
+
+RTDECL(int) RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies)
+{
+ int rc;
+ if (cMillies == RT_INDEFINITE_WAIT)
+ rc = RTSemEventMultiWaitEx(hEventMultiSem, RTSEMWAIT_FLAGS_NORESUME | RTSEMWAIT_FLAGS_INDEFINITE, 0);
+ else
+ rc = RTSemEventMultiWaitEx(hEventMultiSem,
+ RTSEMWAIT_FLAGS_NORESUME | RTSEMWAIT_FLAGS_RELATIVE | RTSEMWAIT_FLAGS_MILLISECS,
+ cMillies);
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTSemEventMultiWaitNoResume);
+
--- /dev/null
+/* $Id: RTSemEventWait-2-ex-generic.cpp $ */
+/** @file
+ * IPRT - RTSemEventWait, implementation based on RTSemEventWaitEx.
+ */
+
+/*
+ * Copyright (C) 2010-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP RTLOGGROUP_SEM
+#define RTSEMEVENT_WITHOUT_REMAPPING
+#include <iprt/semaphore.h>
+#include "internal/iprt.h"
+
+#include <iprt/err.h>
+#include <iprt/assert.h>
+
+
+RTDECL(int) RTSemEventWait(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies)
+{
+ int rc;
+ if (cMillies == RT_INDEFINITE_WAIT)
+ rc = RTSemEventWaitEx(hEventSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_INDEFINITE, 0);
+ else
+ rc = RTSemEventWaitEx(hEventSem,
+ RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_RELATIVE | RTSEMWAIT_FLAGS_MILLISECS,
+ cMillies);
+ Assert(rc != VERR_INTERRUPTED);
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTSemEventWait);
+
--- /dev/null
+/* $Id: RTSemEventWaitNoResume-2-ex-generic.cpp $ */
+/** @file
+ * IPRT - RTSemEventWaitNoResume, generic implementation based
+ * on RTSemEventWaitEx.
+ */
+
+/*
+ * Copyright (C) 2010-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP RTLOGGROUP_SEM
+#define RTSEMEVENT_WITHOUT_REMAPPING
+#include <iprt/semaphore.h>
+#include "internal/iprt.h"
+
+#include <iprt/err.h>
+#include <iprt/assert.h>
+
+
+RTDECL(int) RTSemEventWaitNoResume(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies)
+{
+ int rc;
+ if (cMillies == RT_INDEFINITE_WAIT)
+ rc = RTSemEventWaitEx(hEventSem, RTSEMWAIT_FLAGS_NORESUME | RTSEMWAIT_FLAGS_INDEFINITE, 0);
+ else
+ rc = RTSemEventWaitEx(hEventSem,
+ RTSEMWAIT_FLAGS_NORESUME | RTSEMWAIT_FLAGS_RELATIVE | RTSEMWAIT_FLAGS_MILLISECS,
+ cMillies);
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTSemEventWaitNoResume);
+
--- /dev/null
+/* $Id: errvars-generic.cpp $ */
+/** @file
+ * IPRT - Save and Restore Error Variables, generic stub implementation.
+ */
+
+/*
+ * Copyright (C) 2011-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/err.h>
+#include "internal/iprt.h"
+
+#include <iprt/assert.h>
+#include "internal/magics.h"
+
+
+
+RTDECL(PRTERRVARS) RTErrVarsSave(PRTERRVARS pVars)
+{
+ pVars->ai32Vars[0] = RTERRVARS_MAGIC;
+ return pVars;
+}
+
+
+RTDECL(void) RTErrVarsRestore(PCRTERRVARS pVars)
+{
+ Assert(pVars->ai32Vars[0] == RTERRVARS_MAGIC);
+ RT_NOREF_PV(pVars);
+}
+
+
+RTDECL(bool) RTErrVarsAreEqual(PCRTERRVARS pVars1, PCRTERRVARS pVars2)
+{
+ Assert(pVars1->ai32Vars[0] == RTERRVARS_MAGIC);
+ Assert(pVars2->ai32Vars[0] == RTERRVARS_MAGIC);
+
+ return pVars1->ai32Vars[0] == pVars2->ai32Vars[0];
+}
+
+
+RTDECL(bool) RTErrVarsHaveChanged(PCRTERRVARS pVars)
+{
+ Assert(pVars->ai32Vars[0] == RTERRVARS_MAGIC);
+ RT_NOREF_PV(pVars);
+ return false;
+}
+
--- /dev/null
+/* $Id: mppresent-generic.cpp $ */
+/** @file
+ * IPRT - Multiprocessor, Stubs for the RTMp*Present* API.
+ */
+
+/*
+ * Copyright (C) 2008-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/mp.h>
+#include "internal/iprt.h"
+
+
+RTDECL(PRTCPUSET) RTMpGetPresentSet(PRTCPUSET pSet)
+{
+ return RTMpGetSet(pSet);
+}
+RT_EXPORT_SYMBOL(RTMpGetPresentSet);
+
+
+RTDECL(RTCPUID) RTMpGetPresentCount(void)
+{
+ return RTMpGetCount();
+}
+RT_EXPORT_SYMBOL(RTMpGetPresentCount);
+
+
+RTDECL(RTCPUID) RTMpGetPresentCoreCount(void)
+{
+ return RTMpGetCoreCount();
+}
+RT_EXPORT_SYMBOL(RTMpGetPresentCoreCount);
+
+
+RTDECL(bool) RTMpIsCpuPresent(RTCPUID idCpu)
+{
+ return RTMpIsCpuPossible(idCpu);
+}
+RT_EXPORT_SYMBOL(RTMpIsCpuPresent);
+
--- /dev/null
+/* $Id: rtStrFormatKernelAddress-generic.cpp $ */
+/** @file
+ * IPRT - IPRT String Formatter, ring-0 addresses.
+ */
+
+/*
+ * Copyright (C) 2006-2017 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP RTLOGGROUP_STRING
+#include <iprt/string.h>
+#include "internal/iprt.h"
+
+#include <iprt/assert.h>
+#include <iprt/string.h>
+
+#include "internal/string.h"
+
+
+
+DECLHIDDEN(size_t) rtStrFormatKernelAddress(char *pszBuf, size_t cbBuf, RTR0INTPTR uPtr, signed int cchWidth,
+ signed int cchPrecision, unsigned int fFlags)
+{
+#ifndef DEBUG
+ RT_NOREF(uPtr, cchWidth, cchPrecision);
+# if R0_ARCH_BITS == 64
+ static const char s_szObfuscated[] = "0xXXXXXXXXXXXXXXXX";
+# else
+ static const char s_szObfuscated[] = "0xXXXXXXXX";
+# endif
+ size_t cbSrc = sizeof(s_szObfuscated);
+ const char *pszSrc = s_szObfuscated;
+ if (!(fFlags & RTSTR_F_SPECIAL))
+ {
+ pszSrc += 2;
+ cbSrc -= 2;
+ }
+ if (cbSrc <= cbBuf)
+ {
+ memcpy(pszBuf, pszSrc, cbSrc);
+ return cbSrc - 1;
+ }
+ AssertFailed();
+ memcpy(pszBuf, pszSrc, cbBuf);
+ pszBuf[cbBuf - 1] = '\0';
+ return cbBuf - 1;
+
+#else /* DEBUG */
+ Assert(cbBuf >= 64);
+ return RTStrFormatNumber(pszBuf, uPtr, 16, cchWidth, cchPrecision, fFlags);
+#endif /* DEBUG */
+}
+
--- /dev/null
+../include
\ No newline at end of file
--- /dev/null
+#ifndef ___product_generated_h___
+#define ___product_generated_h___
+
+#define VBOX_VENDOR "Oracle Corporation"
+#define VBOX_VENDOR_SHORT "Oracle"
+#define VBOX_PRODUCT "Oracle VM VirtualBox"
+#define VBOX_BUILD_PUBLISHER "_Ubuntu"
+#define VBOX_C_YEAR "2017"
+
+#endif
--- /dev/null
+../r0drv
\ No newline at end of file
--- /dev/null
+#define VBOX_SVN_REV 117968
--- /dev/null
+#ifndef ___version_generated_h___
+#define ___version_generated_h___
+
+#define VBOX_VERSION_MAJOR 5
+#define VBOX_VERSION_MINOR 1
+#define VBOX_VERSION_BUILD 28
+#define VBOX_VERSION_STRING_RAW "5.1.28"
+#define VBOX_VERSION_STRING "5.1.28_Ubuntu"
+#define VBOX_API_VERSION_STRING "5_1"
+
+#define VBOX_PRIVATE_BUILD_DESC "Private build by buildd"
+
+#endif
--- /dev/null
+/* $Id: GenericRequest.cpp $ */
+/** @file
+ * VBoxGuestLibR0 - Generic VMMDev request management.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#include "VBGLInternal.h"
+#include <iprt/asm.h>
+#include <iprt/asm-amd64-x86.h>
+#include <iprt/assert.h>
+#include <iprt/string.h>
+
+
+DECLVBGL(int) VbglGRVerify(const VMMDevRequestHeader *pReq, size_t cbReq)
+{
+ size_t cbReqExpected;
+
+ if (RT_UNLIKELY(!pReq || cbReq < sizeof(VMMDevRequestHeader)))
+ {
+ dprintf(("VbglGRVerify: Invalid parameter: pReq = %p, cbReq = %zu\n", pReq, cbReq));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ if (RT_UNLIKELY(pReq->size > cbReq))
+ {
+ dprintf(("VbglGRVerify: request size %u > buffer size %zu\n", pReq->size, cbReq));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ /* The request size must correspond to the request type. */
+ cbReqExpected = vmmdevGetRequestSize(pReq->requestType);
+ if (RT_UNLIKELY(cbReq < cbReqExpected))
+ {
+ dprintf(("VbglGRVerify: buffer size %zu < expected size %zu\n", cbReq, cbReqExpected));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ if (cbReqExpected == cbReq)
+ {
+ /*
+ * This is most likely a fixed size request, and in this case the
+ * request size must be also equal to the expected size.
+ */
+ if (RT_UNLIKELY(pReq->size != cbReqExpected))
+ {
+ dprintf(("VbglGRVerify: request size %u != expected size %zu\n", pReq->size, cbReqExpected));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * This can be a variable size request. Check the request type and limit the size
+ * to VMMDEV_MAX_VMMDEVREQ_SIZE, which is max size supported by the host.
+ *
+ * Note: Keep this list sorted for easier human lookup!
+ */
+ if ( pReq->requestType == VMMDevReq_ChangeMemBalloon
+#ifdef VBOX_WITH_64_BITS_GUESTS
+ || pReq->requestType == VMMDevReq_HGCMCall32
+ || pReq->requestType == VMMDevReq_HGCMCall64
+#else
+ || pReq->requestType == VMMDevReq_HGCMCall
+#endif
+ || pReq->requestType == VMMDevReq_RegisterSharedModule
+ || pReq->requestType == VMMDevReq_ReportGuestUserState
+ || pReq->requestType == VMMDevReq_LogString
+ || pReq->requestType == VMMDevReq_SetPointerShape
+ || pReq->requestType == VMMDevReq_VideoSetVisibleRegion)
+ {
+ if (RT_UNLIKELY(cbReq > VMMDEV_MAX_VMMDEVREQ_SIZE))
+ {
+ dprintf(("VbglGRVerify: VMMDevReq_LogString: buffer size %zu too big\n", cbReq));
+ return VERR_BUFFER_OVERFLOW; /** @todo is this error code ok? */
+ }
+ }
+ else
+ {
+ dprintf(("VbglGRVerify: request size %u > buffer size %zu\n", pReq->size, cbReq));
+ return VERR_IO_BAD_LENGTH; /** @todo is this error code ok? */
+ }
+
+ return VINF_SUCCESS;
+}
+
+DECLVBGL(int) VbglGRAlloc(VMMDevRequestHeader **ppReq, size_t cbReq, VMMDevRequestType enmReqType)
+{
+ int rc = vbglR0Enter();
+ if (RT_SUCCESS(rc))
+ {
+ if ( ppReq
+ && cbReq >= sizeof(VMMDevRequestHeader)
+ && cbReq == (uint32_t)cbReq)
+ {
+ VMMDevRequestHeader *pReq = (VMMDevRequestHeader *)VbglPhysHeapAlloc((uint32_t)cbReq);
+ AssertMsgReturn(pReq, ("VbglGRAlloc: no memory (cbReq=%u)\n", cbReq), VERR_NO_MEMORY);
+ memset(pReq, 0xAA, cbReq);
+
+ pReq->size = (uint32_t)cbReq;
+ pReq->version = VMMDEV_REQUEST_HEADER_VERSION;
+ pReq->requestType = enmReqType;
+ pReq->rc = VERR_GENERAL_FAILURE;
+ pReq->reserved1 = 0;
+ pReq->reserved2 = 0;
+
+ *ppReq = pReq;
+ rc = VINF_SUCCESS;
+ }
+ else
+ {
+ dprintf(("VbglGRAlloc: Invalid parameter: ppReq=%p cbReq=%u\n", ppReq, cbReq));
+ rc = VERR_INVALID_PARAMETER;
+ }
+ }
+ return rc;
+}
+
+DECLVBGL(int) VbglGRPerform(VMMDevRequestHeader *pReq)
+{
+ int rc = vbglR0Enter();
+ if (RT_SUCCESS(rc))
+ {
+ if (pReq)
+ {
+ RTCCPHYS PhysAddr = VbglPhysHeapGetPhysAddr(pReq);
+ if ( PhysAddr != 0
+ && PhysAddr < _4G) /* Port IO is 32 bit. */
+ {
+ ASMOutU32(g_vbgldata.portVMMDev + VMMDEV_PORT_OFF_REQUEST, (uint32_t)PhysAddr);
+ /* Make the compiler aware that the host has changed memory. */
+ ASMCompilerBarrier();
+ rc = pReq->rc;
+ }
+ else
+ rc = VERR_VBGL_INVALID_ADDR;
+ }
+ else
+ rc = VERR_INVALID_PARAMETER;
+ }
+ return rc;
+}
+
+DECLVBGL(void) VbglGRFree(VMMDevRequestHeader *pReq)
+{
+ int rc = vbglR0Enter();
+ if (RT_SUCCESS(rc))
+ VbglPhysHeapFree(pReq);
+}
+
--- /dev/null
+/* $Id: HGCM.cpp $ */
+/** @file
+ * VBoxGuestLib - Host-Guest Communication Manager.
+ *
+ * These public functions can be only used by other drivers. They all
+ * do an IOCTL to VBoxGuest via IDC.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+/* Entire file is ifdef'ed with !VBGL_VBOXGUEST */
+#ifndef VBGL_VBOXGUEST
+
+#include "VBGLInternal.h"
+
+#include <iprt/assert.h>
+#include <iprt/semaphore.h>
+#include <iprt/string.h>
+
+#define VBGL_HGCM_ASSERT_MSG AssertReleaseMsg
+
+/**
+ * Initializes the HGCM VBGL bits.
+ *
+ * @return VBox status code.
+ */
+int vbglR0HGCMInit(void)
+{
+ return RTSemFastMutexCreate(&g_vbgldata.mutexHGCMHandle);
+}
+
+/**
+ * Initializes the HGCM VBGL bits.
+ *
+ * @return VBox status code.
+ */
+int vbglR0HGCMTerminate(void)
+{
+ RTSemFastMutexDestroy(g_vbgldata.mutexHGCMHandle);
+ g_vbgldata.mutexHGCMHandle = NIL_RTSEMFASTMUTEX;
+
+ return VINF_SUCCESS;
+}
+
+DECLINLINE(int) vbglHandleHeapEnter(void)
+{
+ int rc = RTSemFastMutexRequest(g_vbgldata.mutexHGCMHandle);
+
+ VBGL_HGCM_ASSERT_MSG(RT_SUCCESS(rc), ("Failed to request handle heap mutex, rc = %Rrc\n", rc));
+
+ return rc;
+}
+
+DECLINLINE(void) vbglHandleHeapLeave(void)
+{
+ RTSemFastMutexRelease(g_vbgldata.mutexHGCMHandle);
+}
+
+struct VBGLHGCMHANDLEDATA *vbglHGCMHandleAlloc(void)
+{
+ struct VBGLHGCMHANDLEDATA *p = NULL;
+ int rc = vbglHandleHeapEnter();
+ if (RT_SUCCESS(rc))
+ {
+ uint32_t i;
+
+ /* Simple linear search in array. This will be called not so often, only connect/disconnect. */
+ /** @todo bitmap for faster search and other obvious optimizations. */
+ for (i = 0; i < RT_ELEMENTS(g_vbgldata.aHGCMHandleData); i++)
+ {
+ if (!g_vbgldata.aHGCMHandleData[i].fAllocated)
+ {
+ p = &g_vbgldata.aHGCMHandleData[i];
+ p->fAllocated = 1;
+ break;
+ }
+ }
+
+ vbglHandleHeapLeave();
+
+ VBGL_HGCM_ASSERT_MSG(p != NULL, ("Not enough HGCM handles.\n"));
+ }
+ return p;
+}
+
+void vbglHGCMHandleFree(struct VBGLHGCMHANDLEDATA *pHandle)
+{
+ if (pHandle)
+ {
+ int rc = vbglHandleHeapEnter();
+ if (RT_SUCCESS(rc))
+ {
+ VBGL_HGCM_ASSERT_MSG(pHandle->fAllocated, ("Freeing not allocated handle.\n"));
+
+ RT_ZERO(*pHandle);
+ vbglHandleHeapLeave();
+ }
+ }
+}
+
+DECLVBGL(int) VbglHGCMConnect(VBGLHGCMHANDLE *pHandle, VBoxGuestHGCMConnectInfo *pData)
+{
+ int rc;
+ if (pHandle && pData)
+ {
+ struct VBGLHGCMHANDLEDATA *pHandleData = vbglHGCMHandleAlloc();
+ if (pHandleData)
+ {
+ rc = vbglDriverOpen(&pHandleData->driver);
+ if (RT_SUCCESS(rc))
+ {
+ rc = vbglDriverIOCtl(&pHandleData->driver, VBOXGUEST_IOCTL_HGCM_CONNECT, pData, sizeof(*pData));
+ if (RT_SUCCESS(rc))
+ rc = pData->result;
+ if (RT_SUCCESS(rc))
+ {
+ *pHandle = pHandleData;
+ return rc;
+ }
+
+ vbglDriverClose(&pHandleData->driver);
+ }
+
+ vbglHGCMHandleFree(pHandleData);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ }
+ else
+ rc = VERR_INVALID_PARAMETER;
+ return rc;
+}
+
+DECLVBGL(int) VbglHGCMDisconnect(VBGLHGCMHANDLE handle, VBoxGuestHGCMDisconnectInfo *pData)
+{
+ int rc = vbglDriverIOCtl(&handle->driver, VBOXGUEST_IOCTL_HGCM_DISCONNECT, pData, sizeof(*pData));
+
+ vbglDriverClose(&handle->driver);
+
+ vbglHGCMHandleFree(handle);
+
+ return rc;
+}
+
+DECLVBGL(int) VbglHGCMCall(VBGLHGCMHANDLE handle, VBoxGuestHGCMCallInfo *pData, uint32_t cbData)
+{
+ VBGL_HGCM_ASSERT_MSG(cbData >= sizeof(VBoxGuestHGCMCallInfo) + pData->cParms * sizeof(HGCMFunctionParameter),
+ ("cbData = %d, cParms = %d (calculated size %d)\n", cbData, pData->cParms,
+ sizeof(VBoxGuestHGCMCallInfo) + pData->cParms * sizeof(VBoxGuestHGCMCallInfo)));
+
+ return vbglDriverIOCtl(&handle->driver, VBOXGUEST_IOCTL_HGCM_CALL(cbData), pData, cbData);
+}
+
+DECLVBGL(int) VbglHGCMCallUserData (VBGLHGCMHANDLE handle, VBoxGuestHGCMCallInfo *pData, uint32_t cbData)
+{
+ VBGL_HGCM_ASSERT_MSG(cbData >= sizeof(VBoxGuestHGCMCallInfo) + pData->cParms * sizeof(HGCMFunctionParameter),
+ ("cbData = %d, cParms = %d (calculated size %d)\n", cbData, pData->cParms,
+ sizeof(VBoxGuestHGCMCallInfo) + pData->cParms * sizeof(VBoxGuestHGCMCallInfo)));
+
+ return vbglDriverIOCtl(&handle->driver, VBOXGUEST_IOCTL_HGCM_CALL_USERDATA(cbData), pData, cbData);
+}
+
+
+DECLVBGL(int) VbglHGCMCallTimed(VBGLHGCMHANDLE handle, VBoxGuestHGCMCallInfoTimed *pData, uint32_t cbData)
+{
+ uint32_t cbExpected = sizeof(VBoxGuestHGCMCallInfoTimed)
+ + pData->info.cParms * sizeof(HGCMFunctionParameter);
+ VBGL_HGCM_ASSERT_MSG(cbData >= cbExpected,
+ ("cbData = %d, cParms = %d (calculated size %d)\n", cbData, pData->info.cParms, cbExpected));
+ NOREF(cbExpected);
+
+ return vbglDriverIOCtl(&handle->driver, VBOXGUEST_IOCTL_HGCM_CALL_TIMED(cbData), pData, cbData);
+}
+
+#endif /* !VBGL_VBOXGUEST */
+
--- /dev/null
+/* $Id: Init.cpp $ */
+/** @file
+ * VBoxGuestLibR0 - Library initialization.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define VBGL_DECL_DATA
+#include "VBGLInternal.h"
+
+#include <iprt/string.h>
+#include <iprt/assert.h>
+#include <iprt/semaphore.h>
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/** The global VBGL instance data. */
+VBGLDATA g_vbgldata;
+
+/**
+ * Used by vbglQueryDriverInfo and VbglInit to try get the host feature mask and
+ * version information (g_vbgldata::hostVersion).
+ *
+ * This was first implemented by the host in 3.1 and we quietly ignore failures
+ * for that reason.
+ */
+static void vbglR0QueryHostVersion (void)
+{
+ VMMDevReqHostVersion *pReq;
+
+ int rc = VbglGRAlloc ((VMMDevRequestHeader **) &pReq, sizeof (*pReq), VMMDevReq_GetHostVersion);
+
+ if (RT_SUCCESS (rc))
+ {
+ rc = VbglGRPerform (&pReq->header);
+
+ if (RT_SUCCESS (rc))
+ {
+ g_vbgldata.hostVersion = *pReq;
+ Log (("vbglR0QueryHostVersion: %u.%u.%ur%u %#x\n",
+ pReq->major, pReq->minor, pReq->build, pReq->revision, pReq->features));
+ }
+
+ VbglGRFree (&pReq->header);
+ }
+}
+
+#ifndef VBGL_VBOXGUEST
+/**
+ * The guest library uses lazy initialization for VMMDev port and memory,
+ * because these values are provided by the VBoxGuest driver and it might
+ * be loaded later than other drivers.
+ *
+ * The VbglEnter checks the current library status, tries to retrieve these
+ * values and fails if they are unavailable.
+ *
+ */
+static void vbglQueryDriverInfo (void)
+{
+ int rc = VINF_SUCCESS;
+
+ rc = RTSemMutexRequest(g_vbgldata.mutexDriverInit, RT_INDEFINITE_WAIT);
+
+ if (RT_FAILURE(rc))
+ return;
+
+ if (g_vbgldata.status == VbglStatusReady)
+ {
+ RTSemMutexRelease(g_vbgldata.mutexDriverInit);
+ return;
+ }
+
+ rc = vbglDriverOpen(&g_vbgldata.driver);
+
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Try query the port info.
+ */
+ VBoxGuestPortInfo port;
+
+ rc = vbglDriverIOCtl (&g_vbgldata.driver,
+ VBOXGUEST_IOCTL_GETVMMDEVPORT, &port,
+ sizeof (port));
+
+ if (RT_SUCCESS (rc))
+ {
+ dprintf (("port = 0x%04X, mem = %p\n", port.portAddress, port.pVMMDevMemory));
+
+ g_vbgldata.portVMMDev = (RTIOPORT)port.portAddress;
+ g_vbgldata.pVMMDevMemory = port.pVMMDevMemory;
+
+ g_vbgldata.status = VbglStatusReady;
+
+ vbglR0QueryHostVersion();
+ }
+ }
+ RTSemMutexRelease(g_vbgldata.mutexDriverInit);
+ dprintf (("vbglQueryDriverInfo rc = %d\n", rc));
+}
+#endif /* !VBGL_VBOXGUEST */
+
+/**
+ * Checks if VBGL has been initialized.
+ *
+ * The client library, this will lazily complete the initialization.
+ *
+ * @return VINF_SUCCESS or VERR_VBGL_NOT_INITIALIZED.
+ */
+int vbglR0Enter (void)
+{
+ int rc;
+
+#ifndef VBGL_VBOXGUEST
+ if (g_vbgldata.status == VbglStatusInitializing)
+ {
+ vbglQueryDriverInfo ();
+ }
+#endif
+
+ rc = g_vbgldata.status == VbglStatusReady? VINF_SUCCESS: VERR_VBGL_NOT_INITIALIZED;
+
+ // dprintf(("VbglEnter: rc = %d\n", rc));
+
+ return rc;
+}
+
+int vbglInitCommon (void)
+{
+ int rc = VINF_SUCCESS;
+
+ RT_ZERO(g_vbgldata);
+
+ g_vbgldata.status = VbglStatusInitializing;
+
+ rc = VbglPhysHeapInit ();
+
+ if (RT_SUCCESS(rc))
+ {
+ /* other subsystems, none yet */
+ ;
+ }
+ else
+ {
+ LogRel(("vbglInitCommon: VbglPhysHeapInit failed. rc=%Rrc\n", rc));
+ g_vbgldata.status = VbglStatusNotInitialized;
+ }
+
+ dprintf(("vbglInitCommon: rc = %d\n", rc));
+
+ return rc;
+}
+
+DECLVBGL(void) vbglTerminateCommon (void)
+{
+ VbglPhysHeapTerminate ();
+ g_vbgldata.status = VbglStatusNotInitialized;
+
+ return;
+}
+
+#ifdef VBGL_VBOXGUEST
+
+DECLVBGL(int) VbglInitPrimary(RTIOPORT portVMMDev, VMMDevMemory *pVMMDevMemory)
+{
+ int rc = VINF_SUCCESS;
+
+# ifdef RT_OS_WINDOWS /** @todo r=bird: this doesn't make sense. Is there something special going on on windows? */
+ dprintf(("vbglInit: starts g_vbgldata.status %d\n", g_vbgldata.status));
+
+ if ( g_vbgldata.status == VbglStatusInitializing
+ || g_vbgldata.status == VbglStatusReady)
+ {
+ /* Initialization is already in process. */
+ return rc;
+ }
+# else
+ dprintf(("vbglInit: starts\n"));
+# endif
+
+ rc = vbglInitCommon ();
+
+ if (RT_SUCCESS(rc))
+ {
+ g_vbgldata.portVMMDev = portVMMDev;
+ g_vbgldata.pVMMDevMemory = pVMMDevMemory;
+
+ g_vbgldata.status = VbglStatusReady;
+
+ vbglR0QueryHostVersion();
+ }
+ else
+ {
+ g_vbgldata.status = VbglStatusNotInitialized;
+ }
+
+ return rc;
+}
+
+DECLVBGL(void) VbglTerminate (void)
+{
+ vbglTerminateCommon ();
+
+ return;
+}
+
+
+#else /* !VBGL_VBOXGUEST */
+
+DECLVBGL(int) VbglInitClient(void)
+{
+ int rc = VINF_SUCCESS;
+
+ if ( g_vbgldata.status == VbglStatusInitializing
+ || g_vbgldata.status == VbglStatusReady)
+ {
+ /* Initialization is already in process. */
+ return rc;
+ }
+
+ rc = vbglInitCommon ();
+
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTSemMutexCreate(&g_vbgldata.mutexDriverInit);
+ if (RT_SUCCESS(rc))
+ {
+ /* Try to obtain VMMDev port via IOCTL to VBoxGuest main driver. */
+ vbglQueryDriverInfo ();
+
+# ifdef VBOX_WITH_HGCM
+ rc = vbglR0HGCMInit ();
+# endif /* VBOX_WITH_HGCM */
+
+ if (RT_FAILURE(rc))
+ {
+ RTSemMutexDestroy(g_vbgldata.mutexDriverInit);
+ g_vbgldata.mutexDriverInit = NIL_RTSEMMUTEX;
+ }
+ }
+
+ if (RT_FAILURE(rc))
+ {
+ vbglTerminateCommon ();
+ }
+
+ }
+
+ return rc;
+}
+
+DECLVBGL(void) VbglTerminate (void)
+{
+# ifdef VBOX_WITH_HGCM
+ vbglR0HGCMTerminate ();
+# endif
+
+ /* driver open could fail, which does not prevent VbglInit from succeeding,
+ * close the driver only if it is opened */
+ if (vbglDriverIsOpened(&g_vbgldata.driver))
+ vbglDriverClose(&g_vbgldata.driver);
+ RTSemMutexDestroy(g_vbgldata.mutexDriverInit);
+ g_vbgldata.mutexDriverInit = NIL_RTSEMMUTEX;
+
+ /* note: do vbglTerminateCommon as a last step since it zeroez up the g_vbgldata
+ * conceptually, doing vbglTerminateCommon last is correct
+ * since this is the reverse order to how init is done */
+ vbglTerminateCommon ();
+
+ return;
+}
+
+int vbglGetDriver(VBGLDRIVER **ppDriver)
+{
+ if (g_vbgldata.status != VbglStatusReady)
+ {
+ vbglQueryDriverInfo();
+ if (g_vbgldata.status != VbglStatusReady)
+ return VERR_TRY_AGAIN;
+ }
+ *ppDriver = &g_vbgldata.driver;
+ return VINF_SUCCESS;
+}
+
+#endif /* !VBGL_VBOXGUEST */
--- /dev/null
+KBUILD_EXTMOD=${srctree}/ubuntu/vbox
+#
+# VirtualBox Guest Additions Module Makefile.
+#
+# (For 2.6.x this file must be 'Makefile'!)
+#
+# Copyright (C) 2006-2011 Oracle Corporation
+#
+# This file is part of VirtualBox Open Source Edition (OSE), as
+# available from http://www.virtualbox.org. This file is free software;
+# you can redistribute it and/or modify it under the terms of the GNU
+# General Public License (GPL) as published by the Free Software
+# Foundation, in version 2 as it comes in the "COPYING" file of the
+# VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+#
+
+# Linux kbuild sets this to our source directory if we are called from there
+obj ?= $(CURDIR)
+include $(obj)/Makefile.include.header
+
+MOD_NAME = vboxsf
+MOD_OBJS = \
+ vfsmod.o \
+ dirops.o \
+ lnkops.o \
+ regops.o \
+ utils.o \
+ GenericRequest.o \
+ SysHlp.o \
+ PhysHeap.o \
+ Init.o \
+ VMMDev.o \
+ HGCM.o \
+ VBoxGuestR0LibSharedFolders.o \
+ VbglR0CanUsePhysPageList.o
+ifeq ($(BUILD_TARGET_ARCH),x86)
+MOD_OBJS += \
+ divdi3.o \
+ moddi3.o \
+ udivdi3.o \
+ udivmoddi4.o \
+ umoddi3.o \
+ qdivrem.o
+endif
+
+MOD_INCL = \
+ $(addprefix -I$(KBUILD_EXTMOD),/ /include /r0drv/linux) \
+ $(addprefix -I$(KBUILD_EXTMOD)/vboxsf,/ /include /r0drv/linux)
+
+ifneq ($(wildcard $(KBUILD_EXTMOD)/vboxsf),)
+ MANGLING := $(KBUILD_EXTMOD)/vboxsf/include/VBox/VBoxGuestMangling.h
+else
+ MANGLING := $(KBUILD_EXTMOD)/include/VBox/VBoxGuestMangling.h
+endif
+
+MOD_DEFS = -DRT_OS_LINUX -DIN_RING0 -DIN_RT_R0 \
+ -DIN_SUP_R0 -DVBOX -DVBOX_WITH_HGCM -DIN_MODULE -DIN_GUEST_R0
+# our module does not export any symbol
+MOD_DEFS += -DRT_NO_EXPORT_SYMBOL
+ifeq ($(BUILD_TARGET_ARCH),amd64)
+ MOD_DEFS += -DRT_ARCH_AMD64 -DVBOX_WITH_64_BITS_GUESTS
+else
+ MOD_DEFS += -DRT_ARCH_X86
+endif
+
+ifeq ($(KERN_VERSION), 24)
+ MOD_CFLAGS =
+else
+ MOD_CFLAGS = -Wno-declaration-after-statement -fshort-wchar -include $(MANGLING) -fno-pie
+
+# special hack for Fedora Core 6 2.6.18 (fc6), rhel5 2.6.18 (el5),
+# ClarkConnect 4.3 (cc4) and ClarkConnect 5 (v5)
+ ifeq ($(KERNELRELEASE),)
+ MOD_EXTRA += $(foreach inc,$(KERN_INCL),\
+ $(if $(wildcard $(inc)/linux/utsrelease.h),\
+ $(if $(shell grep '"2.6.18.*fc6.*"' $(inc)/linux/utsrelease.h; \
+ grep '"2.6.18.*el5.*"' $(inc)/linux/utsrelease.h; \
+ grep '"2.6.18.*v5.*"' $(inc)/linux/utsrelease.h; \
+ grep '"2.6.18.*cc4.*"' $(inc)/linux/utsrelease.h),\
+ -DKERNEL_FC6,),))
+ else
+ MOD_EXTRA += $(if $(shell echo "$(KERNELRELEASE)"|grep '2.6.18.*fc6.*';\
+ echo "$(KERNELRELEASE)"|grep '2.6.18.*el5.*';\
+ echo "$(KERNELRELEASE)"|grep '2.6.18.*v5.*';\
+ echo "$(KERNELRELEASE)"|grep '2.6.18.*cc4.*'),\
+ -DKERNEL_FC6,)
+ endif
+endif
+
+MOD_CLEAN = . linux r0drv r0drv/linux
+
+include $(obj)/Makefile.include.footer
--- /dev/null
+#
+# VirtualBox Guest Additions kernel module Makefile, common parts.
+#
+# See Makefile.include.header for details of how to use this.
+#
+# Copyright (C) 2006-2015 Oracle Corporation
+#
+# This file is part of VirtualBox Open Source Edition (OSE), as
+# available from http://www.virtualbox.org. This file is free software;
+# you can redistribute it and/or modify it under the terms of the GNU
+# General Public License (GPL) as published by the Free Software
+# Foundation, in version 2 as it comes in the "COPYING" file of the
+# VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+#
+
+# override is required by the Debian guys
+override MODULE = $(MOD_NAME)
+OBJS = $(MOD_OBJS)
+
+ifneq ($(MAKECMDGOALS),clean)
+
+KBUILD_VERBOSE ?= 1
+
+#
+# Compiler options
+#
+ifndef INCL
+ INCL := $(addprefix -I,$(KERN_INCL) $(EXTRA_INCL))
+ ifndef KBUILD_EXTMOD
+ KBUILD_EXTMOD := $(shell pwd)
+ endif
+ INCL += $(MOD_INCL)
+ export INCL
+endif
+KFLAGS := -D__KERNEL__ -DMODULE $(MOD_DEFS)
+ifeq ($(BUILD_TYPE),debug)
+ KFLAGS += -DDEBUG -DDEBUG_$(subst $(subst _, ,_),_,$(USERNAME)) -DDEBUG_USERNAME=$(subst $(subst _, ,_),_,$(USERNAME))
+endif
+
+ifeq ($(KERN_VERSION), 24)
+#
+# 2.4
+#
+
+ifeq ($(BUILD_TARGET_ARCH),amd64)
+ KFLAGS += -mcmodel=kernel
+endif
+
+CFLAGS := -O2 -DVBOX_LINUX_2_4 $(MOD_CFLAGS) $(INCL) $(KFLAGS) $(MOD_EXTRA) $(KDEBUG)
+MODULE_EXT := o
+
+# 2.4 Module linking
+$(MODULE).o: $(OBJS)
+ $(LD) -o $@ -r $(OBJS)
+
+.PHONY: $(MODULE)
+all: $(MODULE)
+$(MODULE): $(MODULE).o
+
+else
+#
+# 2.6 and later
+#
+
+MODULE_EXT := ko
+
+$(MODULE)-y := $(OBJS)
+
+# build defs
+EXTRA_CFLAGS += $(MOD_CFLAGS) $(INCL) $(KFLAGS) $(MOD_EXTRA) $(KDEBUG)
+
+.PHONY: $(MODULE)
+all: $(MODULE)
+
+obj-m += $(MODULE).o
+
+JOBS := $(shell (getconf _NPROCESSORS_ONLN || grep -Ec '^processor|^CPU[0-9]' /proc/cpuinfo) 2>/dev/null)
+ifeq ($(JOBS),0)
+ JOBS := 1
+endif
+
+# OL/UEK: disable module signing for external modules -- we don't have any private key
+$(MODULE):
+ $(MAKE) KBUILD_VERBOSE=$(KBUILD_VERBOSE) CONFIG_MODULE_SIG= -C $(KERN_DIR) SUBDIRS=$(CURDIR) SRCROOT=$(CURDIR) -j$(JOBS) modules
+
+modules_install:
+ $(MAKE) KBUILD_VERBOSE=$(KBUILD_VERBOSE) CONFIG_MODULE_SIG= -C $(KERN_DIR) SUBDIRS=$(CURDIR) SRCROOT=$(CURDIR) modules_install
+
+endif
+
+install: $(MODULE)
+ @mkdir -p $(MODULE_DIR); \
+ install -m 0644 -o root -g root $(MODULE).$(MODULE_EXT) $(MODULE_DIR); \
+ PATH="$(PATH):/bin:/sbin" depmod -a;
+
+endif # eq($(MAKECMDGOALS),clean)
+
+clean:
+ for f in $(MOD_CLEAN); do rm -f $$f/*.o $$f/.*.cmd $$f/.*.flags; done
+ rm -rf .$(MOD_NAME)* .tmp_ver* $(MOD_NAME).* Modules.symvers modules.order
--- /dev/null
+#
+# VirtualBox Guest Additions kernel module Makefile, common parts.
+#
+# (For 2.6.x, the main file must be called 'Makefile'!)
+#
+# Copyright (C) 2006-2015 Oracle Corporation
+#
+# This file is part of VirtualBox Open Source Edition (OSE), as
+# available from http://www.virtualbox.org. This file is free software;
+# you can redistribute it and/or modify it under the terms of the GNU
+# General Public License (GPL) as published by the Free Software
+# Foundation, in version 2 as it comes in the "COPYING" file of the
+# VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+#
+
+# Testing:
+# * Building with KERN_VER set to an installed but non-current kernel works and
+# installs to the right location.
+# * Building with KERN_DIR and/or MODULE_DIR set uses the value specified and
+# the default value for the unspecified one if any.
+
+#
+# These file should be included by the Makefiles for any kernel modules we
+# build as part of the Guest Additions. The intended way of doing this is as
+# follows:
+#
+# # Linux kbuild sets this to our source directory if we are called from
+# # there
+# obj ?= $(CURDIR)
+# include $(obj)/Makefile.include.header
+# MOD_NAME = <name of the module to be built, without extension>
+# MOD_OBJS = <list of object files which should be included>
+# MOD_DEFS = <any additional defines which this module needs>
+# MOD_INCL = <any additional include paths which this module needs>
+# MOD_CFLAGS = <any additional CFLAGS which this module needs>
+# MOD_CLEAN = <list of directories that the clean target should look at>
+# include $(obj)/Makefile.include.footer
+#
+# The kmk kBuild define KBUILD_TARGET_ARCH is available.
+#
+
+
+#
+# First, figure out which architecture we're targeting and the build type.
+# (We have to support basic cross building (ARCH=i386|x86_64).)
+# While at it, warn about BUILD_* vars found to help with user problems.
+#
+ifeq ($(filter-out x86_64 amd64 AMD64,$(shell uname -m)),)
+ BUILD_TARGET_ARCH_DEF := amd64
+else
+ BUILD_TARGET_ARCH_DEF := x86
+endif
+ifneq ($(filter-out amd64 x86,$(BUILD_TARGET_ARCH)),)
+ $(warning Ignoring unknown BUILD_TARGET_ARCH value '$(BUILD_TARGET_ARCH)'.)
+ BUILD_TARGET_ARCH :=
+endif
+ifeq ($(BUILD_TARGET_ARCH),)
+ ifeq ($(ARCH),x86_64)
+ BUILD_TARGET_ARCH := amd64
+ else
+ ifeq ($(ARCH),i386)
+ ifeq ($(CONFIG_X86_32),y)
+ BUILD_TARGET_ARCH := x86
+ else
+ BUILD_TARGET_ARCH := amd64
+ endif
+ else
+ ifeq ($(ARCH),x86)
+ ifeq ($(CONFIG_X86_32),y)
+ BUILD_TARGET_ARCH := x86
+ else
+ BUILD_TARGET_ARCH := amd64
+ endif
+ else
+ BUILD_TARGET_ARCH := $(BUILD_TARGET_ARCH_DEF)
+ endif
+ endif
+ endif
+else
+ ifneq ($(BUILD_TARGET_ARCH),$(BUILD_TARGET_ARCH_DEF))
+ $(warning Using BUILD_TARGET_ARCH='$(BUILD_TARGET_ARCH)' from the $(origin BUILD_TARGET_ARCH).)
+ endif
+endif
+
+ifneq ($(filter-out release profile debug strict,$(BUILD_TYPE)),)
+ $(warning Ignoring unknown BUILD_TYPE value '$(BUILD_TYPE)'.)
+ BUILD_TYPE :=
+endif
+ifeq ($(BUILD_TYPE),)
+ BUILD_TYPE := release
+else
+ ifneq ($(BUILD_TYPE),release)
+ $(warning Using BUILD_TYPE='$(BUILD_TYPE)' from the $(origin BUILD_TYPE).)
+ endif
+endif
+ifeq ($(USERNAME),)
+ USERNAME := noname
+endif
+
+ifneq ($(MAKECMDGOALS),clean)
+
+ifeq ($(KERNELRELEASE),)
+
+ #
+ # building from this directory
+ #
+
+ # target kernel version
+ ifndef KERN_VER
+ KERN_VER := $(shell uname -r)
+ else
+ ifneq ($(shell if test -d /lib/modules/$(KERN_VER)/build; then echo yes; fi),yes)
+ KERN_VER := $(shell uname -r)
+ endif
+ endif
+
+ # kernel base directory
+ ifndef KERN_DIR
+ KERN_DIR := /lib/modules/$(KERN_VER)/build
+ ifneq ($(shell if test -d $(KERN_DIR); then echo yes; fi),yes)
+ KERN_DIR := /usr/src/linux
+ ifneq ($(shell if test -d $(KERN_DIR); then echo yes; fi),yes)
+ $(error Error: unable to find the sources of your current Linux kernel. \
+ Specify KERN_DIR=<directory> and run Make again)
+ endif
+ $(warning Warning: using /usr/src/linux as the source directory of your \
+ Linux kernel. If this is not correct, specify \
+ KERN_DIR=<directory> and run Make again.)
+ endif
+ else
+ ifneq ($(shell if test -d $(KERN_DIR); then echo yes; fi),yes)
+ $(error Error: KERN_DIR does not point to a directory)
+ endif
+ endif
+
+ # includes
+ ifndef KERN_INCL
+ KERN_INCL = $(KERN_DIR)/include
+ endif
+ ifneq ($(shell if test -d $(KERN_INCL); then echo yes; fi),yes)
+ $(error Error: unable to find the include directory for your current Linux \
+ kernel. Specify KERN_INCL=<directory> and run Make again)
+ endif
+
+ # module install dir, only for current kernel
+ ifneq ($(filter install install_rpm,$(MAKECMDGOALS)),)
+ ifndef MODULE_DIR
+ MODULE_DIR_TST := /lib/modules/$(KERN_VER)
+ ifeq ($(shell if test -d $(MODULE_DIR_TST); then echo yes; fi),yes)
+ MODULE_DIR := $(MODULE_DIR_TST)/misc
+ else
+ $(error Unable to find the folder to install the module to)
+ endif
+ endif # MODULE_DIR unspecified
+ endif
+
+ # guess kernel version (24 or 26)
+ ifeq ($(shell if grep '"2\.4\.' $(KERN_INCL)/linux/version.h > /dev/null; then echo yes; fi),yes)
+ KERN_VERSION := 24
+ else
+ KERN_VERSION := 26
+ endif
+
+else # neq($(KERNELRELEASE),)
+
+ #
+ # building from kbuild (make -C <kernel_directory> M=`pwd`)
+ #
+
+ # guess kernel version (24 or 26)
+ ifeq ($(shell if echo "$(VERSION).$(PATCHLEVEL)." | grep '2\.4\.' > /dev/null; then echo yes; fi),yes)
+ KERN_VERSION := 24
+ else
+ KERN_VERSION := 26
+ endif
+
+endif # neq($(KERNELRELEASE),)
+
+# debug - show guesses.
+ifdef DEBUG
+$(warning dbg: KERN_DIR = $(KERN_DIR))
+$(warning dbg: KERN_INCL = $(KERN_INCL))
+$(warning dbg: MODULE_DIR = $(MODULE_DIR))
+$(warning dbg: KERN_VERSION = $(KERN_VERSION))
+endif
+
+endif # eq($(MAKECMDGOALS),clean)
--- /dev/null
+/* $Id: PhysHeap.cpp $ */
+/** @file
+ * VBoxGuestLibR0 - Physical memory heap.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#include "VBGLInternal.h"
+
+#include <iprt/assert.h>
+#include <iprt/semaphore.h>
+#include <iprt/alloc.h>
+
+/* Physical memory heap consists of double linked list
+ * of chunks. Memory blocks are allocated inside these chunks
+ * and are members of Allocated and Free double linked lists.
+ *
+ * When allocating a block, we search in Free linked
+ * list for a suitable free block. If there is no such block,
+ * a new chunk is allocated and the new block is taken from
+ * the new chunk as the only chunk-sized free block.
+ * Allocated block is excluded from the Free list and goes to
+ * Alloc list.
+ *
+ * When freeing block, we check the pointer and then
+ * exclude block from Alloc list and move it to free list.
+ *
+ * For each chunk we maintain the allocated blocks counter.
+ * if 2 (or more) entire chunks are free they are immediately
+ * deallocated, so we always have at most 1 free chunk.
+ *
+ * When freeing blocks, two subsequent free blocks are always
+ * merged together. Current implementation merges blocks only
+ * when there is a block after the just freed one.
+ *
+ */
+
+#define VBGL_PH_ASSERT Assert
+#define VBGL_PH_ASSERTMsg AssertMsg
+
+// #define DUMPHEAP
+
+#ifdef DUMPHEAP
+# define VBGL_PH_dprintf(a) RTAssertMsg2Weak a
+#else
+# define VBGL_PH_dprintf(a)
+#endif
+
+/* Heap block signature */
+#define VBGL_PH_BLOCKSIGNATURE (0xADDBBBBB)
+
+
+/* Heap chunk signature */
+#define VBGL_PH_CHUNKSIGNATURE (0xADDCCCCC)
+/* Heap chunk allocation unit */
+#define VBGL_PH_CHUNKSIZE (0x10000)
+
+/* Heap block bit flags */
+#define VBGL_PH_BF_ALLOCATED (0x1)
+
+struct _VBGLPHYSHEAPBLOCK
+{
+ uint32_t u32Signature;
+
+ /* Size of user data in the block. Does not include the block header. */
+ uint32_t cbDataSize;
+
+ uint32_t fu32Flags;
+
+ struct _VBGLPHYSHEAPBLOCK *pNext;
+ struct _VBGLPHYSHEAPBLOCK *pPrev;
+
+ struct _VBGLPHYSHEAPCHUNK *pChunk;
+};
+
+struct _VBGLPHYSHEAPCHUNK
+{
+ uint32_t u32Signature;
+
+ /* Size of the chunk. Includes the chunk header. */
+ uint32_t cbSize;
+
+ /* Physical address of the chunk */
+ uint32_t physAddr;
+
+ /* Number of allocated blocks in the chunk */
+ int32_t cAllocatedBlocks;
+
+ struct _VBGLPHYSHEAPCHUNK *pNext;
+ struct _VBGLPHYSHEAPCHUNK *pPrev;
+};
+
+
+#ifndef DUMPHEAP
+#define dumpheap(a)
+#else
+void dumpheap (char *point)
+{
+ VBGL_PH_dprintf(("VBGL_PH dump at '%s'\n", point));
+
+ VBGL_PH_dprintf(("Chunks:\n"));
+
+ VBGLPHYSHEAPCHUNK *pChunk = g_vbgldata.pChunkHead;
+
+ while (pChunk)
+ {
+ VBGL_PH_dprintf(("%p: pNext = %p, pPrev = %p, sign = %08X, size = %8d, allocated = %8d, phys = %08X\n",
+ pChunk, pChunk->pNext, pChunk->pPrev, pChunk->u32Signature, pChunk->cbSize, pChunk->cAllocatedBlocks, pChunk->physAddr));
+
+ pChunk = pChunk->pNext;
+ }
+
+ VBGL_PH_dprintf(("Allocated blocks:\n"));
+
+ VBGLPHYSHEAPBLOCK *pBlock = g_vbgldata.pAllocBlocksHead;
+
+ while (pBlock)
+ {
+ VBGL_PH_dprintf(("%p: pNext = %p, pPrev = %p, sign = %08X, size = %8d, flags = %08X, pChunk = %p\n",
+ pBlock, pBlock->pNext, pBlock->pPrev, pBlock->u32Signature, pBlock->cbDataSize, pBlock->fu32Flags, pBlock->pChunk));
+
+ pBlock = pBlock->pNext;
+ }
+
+ VBGL_PH_dprintf(("Free blocks:\n"));
+
+ pBlock = g_vbgldata.pFreeBlocksHead;
+
+ while (pBlock)
+ {
+ VBGL_PH_dprintf(("%p: pNext = %p, pPrev = %p, sign = %08X, size = %8d, flags = %08X, pChunk = %p\n",
+ pBlock, pBlock->pNext, pBlock->pPrev, pBlock->u32Signature, pBlock->cbDataSize, pBlock->fu32Flags, pBlock->pChunk));
+
+ pBlock = pBlock->pNext;
+ }
+
+ VBGL_PH_dprintf(("VBGL_PH dump at '%s' done\n", point));
+}
+#endif
+
+
+DECLINLINE(void *) vbglPhysHeapBlock2Data (VBGLPHYSHEAPBLOCK *pBlock)
+{
+ return (void *)(pBlock? (char *)pBlock + sizeof (VBGLPHYSHEAPBLOCK): NULL);
+}
+
+DECLINLINE(VBGLPHYSHEAPBLOCK *) vbglPhysHeapData2Block (void *p)
+{
+ VBGLPHYSHEAPBLOCK *pBlock = (VBGLPHYSHEAPBLOCK *)(p? (char *)p - sizeof (VBGLPHYSHEAPBLOCK): NULL);
+
+ VBGL_PH_ASSERTMsg(pBlock == NULL || pBlock->u32Signature == VBGL_PH_BLOCKSIGNATURE,
+ ("pBlock->u32Signature = %08X\n", pBlock->u32Signature));
+
+ return pBlock;
+}
+
+DECLINLINE(int) vbglPhysHeapEnter (void)
+{
+ int rc = RTSemFastMutexRequest(g_vbgldata.mutexHeap);
+
+ VBGL_PH_ASSERTMsg(RT_SUCCESS(rc),
+ ("Failed to request heap mutex, rc = %Rrc\n", rc));
+
+ return rc;
+}
+
+DECLINLINE(void) vbglPhysHeapLeave (void)
+{
+ RTSemFastMutexRelease(g_vbgldata.mutexHeap);
+}
+
+
+static void vbglPhysHeapInitBlock (VBGLPHYSHEAPBLOCK *pBlock, VBGLPHYSHEAPCHUNK *pChunk, uint32_t cbDataSize)
+{
+ VBGL_PH_ASSERT(pBlock != NULL);
+ VBGL_PH_ASSERT(pChunk != NULL);
+
+ pBlock->u32Signature = VBGL_PH_BLOCKSIGNATURE;
+ pBlock->cbDataSize = cbDataSize;
+ pBlock->fu32Flags = 0;
+ pBlock->pNext = NULL;
+ pBlock->pPrev = NULL;
+ pBlock->pChunk = pChunk;
+}
+
+
+static void vbglPhysHeapInsertBlock (VBGLPHYSHEAPBLOCK *pInsertAfter, VBGLPHYSHEAPBLOCK *pBlock)
+{
+ VBGL_PH_ASSERTMsg(pBlock->pNext == NULL,
+ ("pBlock->pNext = %p\n", pBlock->pNext));
+ VBGL_PH_ASSERTMsg(pBlock->pPrev == NULL,
+ ("pBlock->pPrev = %p\n", pBlock->pPrev));
+
+ if (pInsertAfter)
+ {
+ pBlock->pNext = pInsertAfter->pNext;
+ pBlock->pPrev = pInsertAfter;
+
+ if (pInsertAfter->pNext)
+ {
+ pInsertAfter->pNext->pPrev = pBlock;
+ }
+
+ pInsertAfter->pNext = pBlock;
+ }
+ else
+ {
+ /* inserting to head of list */
+ pBlock->pPrev = NULL;
+
+ if (pBlock->fu32Flags & VBGL_PH_BF_ALLOCATED)
+ {
+ pBlock->pNext = g_vbgldata.pAllocBlocksHead;
+
+ if (g_vbgldata.pAllocBlocksHead)
+ {
+ g_vbgldata.pAllocBlocksHead->pPrev = pBlock;
+ }
+
+ g_vbgldata.pAllocBlocksHead = pBlock;
+ }
+ else
+ {
+ pBlock->pNext = g_vbgldata.pFreeBlocksHead;
+
+ if (g_vbgldata.pFreeBlocksHead)
+ {
+ g_vbgldata.pFreeBlocksHead->pPrev = pBlock;
+ }
+
+ g_vbgldata.pFreeBlocksHead = pBlock;
+ }
+ }
+}
+
+static void vbglPhysHeapExcludeBlock (VBGLPHYSHEAPBLOCK *pBlock)
+{
+ if (pBlock->pNext)
+ {
+ pBlock->pNext->pPrev = pBlock->pPrev;
+ }
+ else
+ {
+ /* this is tail of list but we do not maintain tails of block lists.
+ * so do nothing.
+ */
+ ;
+ }
+
+ if (pBlock->pPrev)
+ {
+ pBlock->pPrev->pNext = pBlock->pNext;
+ }
+ else
+ {
+ /* this is head of list but we do not maintain tails of block lists. */
+ if (pBlock->fu32Flags & VBGL_PH_BF_ALLOCATED)
+ {
+ g_vbgldata.pAllocBlocksHead = pBlock->pNext;
+ }
+ else
+ {
+ g_vbgldata.pFreeBlocksHead = pBlock->pNext;
+ }
+ }
+
+ pBlock->pNext = NULL;
+ pBlock->pPrev = NULL;
+}
+
+static VBGLPHYSHEAPBLOCK *vbglPhysHeapChunkAlloc (uint32_t cbSize)
+{
+ RTCCPHYS physAddr;
+ VBGLPHYSHEAPCHUNK *pChunk;
+ VBGLPHYSHEAPBLOCK *pBlock;
+ VBGL_PH_dprintf(("Allocating new chunk of size %d\n", cbSize));
+
+ /* Compute chunk size to allocate */
+ if (cbSize < VBGL_PH_CHUNKSIZE)
+ {
+ /* Includes case of block size 0 during initialization */
+ cbSize = VBGL_PH_CHUNKSIZE;
+ }
+ else
+ {
+ /* Round up to next chunk size, which must be power of 2 */
+ cbSize = (cbSize + (VBGL_PH_CHUNKSIZE - 1)) & ~(VBGL_PH_CHUNKSIZE - 1);
+ }
+
+ physAddr = 0;
+ /* This function allocates physical contiguous memory (below 4GB) according to the IPRT docs.
+ * Address < 4G is required for the port IO.
+ */
+ pChunk = (VBGLPHYSHEAPCHUNK *)RTMemContAlloc (&physAddr, cbSize);
+
+ if (!pChunk)
+ {
+ LogRel(("vbglPhysHeapChunkAlloc: failed to alloc %u contiguous bytes.\n", cbSize));
+ return NULL;
+ }
+
+ AssertRelease(physAddr < _4G && physAddr + cbSize <= _4G);
+
+ pChunk->u32Signature = VBGL_PH_CHUNKSIGNATURE;
+ pChunk->cbSize = cbSize;
+ pChunk->physAddr = (uint32_t)physAddr;
+ pChunk->cAllocatedBlocks = 0;
+ pChunk->pNext = g_vbgldata.pChunkHead;
+ pChunk->pPrev = NULL;
+
+ /* Initialize the free block, which now occupies entire chunk. */
+ pBlock = (VBGLPHYSHEAPBLOCK *)((char *)pChunk + sizeof (VBGLPHYSHEAPCHUNK));
+
+ vbglPhysHeapInitBlock (pBlock, pChunk, cbSize - sizeof (VBGLPHYSHEAPCHUNK) - sizeof (VBGLPHYSHEAPBLOCK));
+
+ vbglPhysHeapInsertBlock (NULL, pBlock);
+
+ g_vbgldata.pChunkHead = pChunk;
+
+ VBGL_PH_dprintf(("Allocated chunk %p, block = %p size=%x\n", pChunk, pBlock, cbSize));
+
+ return pBlock;
+}
+
+
+void vbglPhysHeapChunkDelete (VBGLPHYSHEAPCHUNK *pChunk)
+{
+ char *p;
+ VBGL_PH_ASSERT(pChunk != NULL);
+ VBGL_PH_ASSERTMsg(pChunk->u32Signature == VBGL_PH_CHUNKSIGNATURE,
+ ("pChunk->u32Signature = %08X\n", pChunk->u32Signature));
+
+ VBGL_PH_dprintf(("Deleting chunk %p size %x\n", pChunk, pChunk->cbSize));
+
+ /* first scan the chunk and exclude all blocks from lists */
+
+ p = (char *)pChunk + sizeof (VBGLPHYSHEAPCHUNK);
+
+ while (p < (char *)pChunk + pChunk->cbSize)
+ {
+ VBGLPHYSHEAPBLOCK *pBlock = (VBGLPHYSHEAPBLOCK *)p;
+
+ p += pBlock->cbDataSize + sizeof (VBGLPHYSHEAPBLOCK);
+
+ vbglPhysHeapExcludeBlock (pBlock);
+ }
+
+ VBGL_PH_ASSERTMsg(p == (char *)pChunk + pChunk->cbSize,
+ ("p = %p, (char *)pChunk + pChunk->cbSize = %p, pChunk->cbSize = %08X\n",
+ p, (char *)pChunk + pChunk->cbSize, pChunk->cbSize));
+
+ /* Exclude chunk from the chunk list */
+ if (pChunk->pNext)
+ {
+ pChunk->pNext->pPrev = pChunk->pPrev;
+ }
+ else
+ {
+ /* we do not maintain tail */
+ ;
+ }
+
+ if (pChunk->pPrev)
+ {
+ pChunk->pPrev->pNext = pChunk->pNext;
+ }
+ else
+ {
+ /* the chunk was head */
+ g_vbgldata.pChunkHead = pChunk->pNext;
+ }
+
+ RTMemContFree (pChunk, pChunk->cbSize);
+}
+
+
+DECLVBGL(void *) VbglPhysHeapAlloc (uint32_t cbSize)
+{
+ VBGLPHYSHEAPBLOCK *pBlock, *iter;
+ int rc = vbglPhysHeapEnter ();
+
+ if (RT_FAILURE(rc))
+ return NULL;
+
+ dumpheap ("pre alloc");
+
+ pBlock = NULL;
+
+ /* If there are free blocks in the heap, look at them. */
+ iter = g_vbgldata.pFreeBlocksHead;
+
+ /* There will be not many blocks in the heap, so
+ * linear search would be fast enough.
+ */
+
+ while (iter)
+ {
+ if (iter->cbDataSize == cbSize)
+ {
+ /* exact match */
+ pBlock = iter;
+ break;
+ }
+
+ /* Looking for a free block with nearest size */
+ if (iter->cbDataSize > cbSize)
+ {
+ if (pBlock)
+ {
+ if (iter->cbDataSize < pBlock->cbDataSize)
+ {
+ pBlock = iter;
+ }
+ }
+ else
+ {
+ pBlock = iter;
+ }
+ }
+
+ iter = iter->pNext;
+ }
+
+ if (!pBlock)
+ {
+ /* No free blocks, allocate a new chunk,
+ * the only free block of the chunk will
+ * be returned.
+ */
+ pBlock = vbglPhysHeapChunkAlloc (cbSize);
+ }
+
+ if (pBlock)
+ {
+ VBGL_PH_ASSERTMsg(pBlock->u32Signature == VBGL_PH_BLOCKSIGNATURE,
+ ("pBlock = %p, pBlock->u32Signature = %08X\n", pBlock, pBlock->u32Signature));
+ VBGL_PH_ASSERTMsg((pBlock->fu32Flags & VBGL_PH_BF_ALLOCATED) == 0,
+ ("pBlock = %p, pBlock->fu32Flags = %08X\n", pBlock, pBlock->fu32Flags));
+
+ /* We have a free block, either found or allocated. */
+
+ if (pBlock->cbDataSize > 2*(cbSize + sizeof (VBGLPHYSHEAPBLOCK)))
+ {
+ /* Data will occupy less than a half of the block,
+ * the block should be split.
+ */
+ iter = (VBGLPHYSHEAPBLOCK *)((char *)pBlock + sizeof (VBGLPHYSHEAPBLOCK) + cbSize);
+
+ /* Init the new 'iter' block, initialized blocks are always marked as free. */
+ vbglPhysHeapInitBlock (iter, pBlock->pChunk, pBlock->cbDataSize - cbSize - sizeof (VBGLPHYSHEAPBLOCK));
+
+ pBlock->cbDataSize = cbSize;
+
+ /* Insert the new 'iter' block after the 'pBlock' in the free list */
+ vbglPhysHeapInsertBlock (pBlock, iter);
+ }
+
+ /* Exclude pBlock from free list */
+ vbglPhysHeapExcludeBlock (pBlock);
+
+ /* Mark as allocated */
+ pBlock->fu32Flags |= VBGL_PH_BF_ALLOCATED;
+
+ /* Insert to allocated list */
+ vbglPhysHeapInsertBlock (NULL, pBlock);
+
+ /* Adjust the chunk allocated blocks counter */
+ pBlock->pChunk->cAllocatedBlocks++;
+ }
+
+ dumpheap ("post alloc");
+
+ vbglPhysHeapLeave ();
+ VBGL_PH_dprintf(("VbglPhysHeapAlloc %x size %x\n", vbglPhysHeapBlock2Data (pBlock), pBlock->cbDataSize));
+
+ return vbglPhysHeapBlock2Data (pBlock);
+}
+
+DECLVBGL(uint32_t) VbglPhysHeapGetPhysAddr (void *p)
+{
+ uint32_t physAddr = 0;
+ VBGLPHYSHEAPBLOCK *pBlock = vbglPhysHeapData2Block (p);
+
+ if (pBlock)
+ {
+ VBGL_PH_ASSERTMsg((pBlock->fu32Flags & VBGL_PH_BF_ALLOCATED) != 0,
+ ("pBlock = %p, pBlock->fu32Flags = %08X\n", pBlock, pBlock->fu32Flags));
+
+ if (pBlock->fu32Flags & VBGL_PH_BF_ALLOCATED)
+ physAddr = pBlock->pChunk->physAddr + (uint32_t)((uintptr_t)p - (uintptr_t)pBlock->pChunk);
+ }
+
+ return physAddr;
+}
+
+DECLVBGL(void) VbglPhysHeapFree(void *p)
+{
+ VBGLPHYSHEAPBLOCK *pBlock;
+ VBGLPHYSHEAPBLOCK *pNeighbour;
+
+ int rc = vbglPhysHeapEnter ();
+ if (RT_FAILURE(rc))
+ return;
+
+ dumpheap ("pre free");
+
+ pBlock = vbglPhysHeapData2Block (p);
+
+ if (!pBlock)
+ {
+ vbglPhysHeapLeave ();
+ return;
+ }
+
+ VBGL_PH_ASSERTMsg((pBlock->fu32Flags & VBGL_PH_BF_ALLOCATED) != 0,
+ ("pBlock = %p, pBlock->fu32Flags = %08X\n", pBlock, pBlock->fu32Flags));
+
+ /* Exclude from allocated list */
+ vbglPhysHeapExcludeBlock (pBlock);
+
+ dumpheap ("post exclude");
+
+ VBGL_PH_dprintf(("VbglPhysHeapFree %x size %x\n", p, pBlock->cbDataSize));
+
+ /* Mark as free */
+ pBlock->fu32Flags &= ~VBGL_PH_BF_ALLOCATED;
+
+ /* Insert to free list */
+ vbglPhysHeapInsertBlock (NULL, pBlock);
+
+ dumpheap ("post insert");
+
+ /* Adjust the chunk allocated blocks counter */
+ pBlock->pChunk->cAllocatedBlocks--;
+
+ VBGL_PH_ASSERT(pBlock->pChunk->cAllocatedBlocks >= 0);
+
+ /* Check if we can merge 2 free blocks. To simplify heap maintenance,
+ * we will look at block after the just freed one.
+ * This will not prevent us from detecting free memory chunks.
+ * Also in most cases blocks are deallocated in reverse allocation order
+ * and in that case the merging will work.
+ */
+
+ pNeighbour = (VBGLPHYSHEAPBLOCK *)((char *)p + pBlock->cbDataSize);
+
+ if ((char *)pNeighbour < (char *)pBlock->pChunk + pBlock->pChunk->cbSize
+ && (pNeighbour->fu32Flags & VBGL_PH_BF_ALLOCATED) == 0)
+ {
+ /* The next block is free as well. */
+
+ /* Adjust size of current memory block */
+ pBlock->cbDataSize += pNeighbour->cbDataSize + sizeof (VBGLPHYSHEAPBLOCK);
+
+ /* Exclude the next neighbour */
+ vbglPhysHeapExcludeBlock (pNeighbour);
+ }
+
+ dumpheap ("post merge");
+
+ /* now check if there are 2 or more free chunks */
+ if (pBlock->pChunk->cAllocatedBlocks == 0)
+ {
+ VBGLPHYSHEAPCHUNK *pChunk = g_vbgldata.pChunkHead;
+
+ uint32_t u32FreeChunks = 0;
+
+ while (pChunk)
+ {
+ if (pChunk->cAllocatedBlocks == 0)
+ {
+ u32FreeChunks++;
+ }
+
+ pChunk = pChunk->pNext;
+ }
+
+ if (u32FreeChunks > 1)
+ {
+ /* Delete current chunk, it will also exclude all free blocks
+ * remaining in the chunk from the free list, so the pBlock
+ * will also be invalid after this.
+ */
+ vbglPhysHeapChunkDelete (pBlock->pChunk);
+ }
+ }
+
+ dumpheap ("post free");
+
+ vbglPhysHeapLeave ();
+}
+
+DECLVBGL(int) VbglPhysHeapInit (void)
+{
+ int rc = VINF_SUCCESS;
+
+ /* Allocate the first chunk of the heap. */
+ VBGLPHYSHEAPBLOCK *pBlock = vbglPhysHeapChunkAlloc (0);
+
+ if (!pBlock)
+ rc = VERR_NO_MEMORY;
+
+ RTSemFastMutexCreate(&g_vbgldata.mutexHeap);
+
+ return rc;
+}
+
+DECLVBGL(void) VbglPhysHeapTerminate (void)
+{
+ while (g_vbgldata.pChunkHead)
+ {
+ vbglPhysHeapChunkDelete (g_vbgldata.pChunkHead);
+ }
+
+ RTSemFastMutexDestroy(g_vbgldata.mutexHeap);
+}
+
--- /dev/null
+/* $Id: SysHlp.cpp $ */
+/** @file
+ * VBoxGuestLibR0 - IDC with VBoxGuest and HGCM helpers.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#define LOG_GROUP LOG_GROUP_HGCM
+#include <VBox/log.h>
+
+#include <VBox/VBoxGuestLib.h>
+#include "SysHlp.h"
+
+#include <iprt/assert.h>
+
+#ifdef VBGL_VBOXGUEST
+
+#if !defined (RT_OS_WINDOWS)
+# include <iprt/memobj.h>
+# include <iprt/mem.h>
+#endif
+
+
+/**
+ * Internal worker for locking a range of linear addresses.
+ *
+ * @returns VBox status code.
+ * @param ppvCtx Where to store context data.
+ * @param pv The start of the range.
+ * @param u32Size The size of the range.
+ * @param fWriteAccess Lock for read-write (true) or readonly (false).
+ * @param fFlags HGCM call flags, VBGLR0_HGCM_F_XXX.
+ */
+int vbglLockLinear(void **ppvCtx, void *pv, uint32_t u32Size, bool fWriteAccess, uint32_t fFlags)
+{
+ int rc = VINF_SUCCESS;
+#ifndef RT_OS_WINDOWS
+ RTR0MEMOBJ MemObj = NIL_RTR0MEMOBJ;
+ uint32_t fAccess = RTMEM_PROT_READ | (fWriteAccess ? RTMEM_PROT_WRITE : 0);
+#endif
+
+ /* Zero size buffers shouldn't be locked. */
+ if (u32Size == 0)
+ {
+ Assert(pv == NULL);
+#ifdef RT_OS_WINDOWS
+ *ppvCtx = NULL;
+#else
+ *ppvCtx = NIL_RTR0MEMOBJ;
+#endif
+ return VINF_SUCCESS;
+ }
+
+ /** @todo just use IPRT here. the extra allocation shouldn't matter much...
+ * Then we can move all this up one level even. */
+#ifdef RT_OS_WINDOWS
+ PMDL pMdl = IoAllocateMdl(pv, u32Size, FALSE, FALSE, NULL);
+
+ if (pMdl == NULL)
+ {
+ rc = VERR_NOT_SUPPORTED;
+ AssertMsgFailed(("IoAllocateMdl %p %x failed!!\n", pv, u32Size));
+ }
+ else
+ {
+ __try {
+ /* Calls to MmProbeAndLockPages must be enclosed in a try/except block. */
+ RT_NOREF1(fFlags); /** @todo fFlags on windows */
+ MmProbeAndLockPages(pMdl,
+ /** @todo (fFlags & VBGLR0_HGCMCALL_F_MODE_MASK) == VBGLR0_HGCMCALL_F_USER? UserMode: KernelMode */
+ KernelMode,
+ (fWriteAccess) ? IoModifyAccess : IoReadAccess);
+
+ *ppvCtx = pMdl;
+
+ } __except(EXCEPTION_EXECUTE_HANDLER) {
+
+ IoFreeMdl(pMdl);
+ /** @todo */
+ rc = VERR_INVALID_PARAMETER;
+ AssertMsgFailed(("MmProbeAndLockPages %p %x failed!!\n", pv, u32Size));
+ }
+ }
+
+#else
+ /*
+ * Lock depending on context.
+ *
+ * Note: We will later use the memory object here to convert the HGCM
+ * linear buffer parameter into a physical page list. This is why
+ * we lock both kernel pages on all systems, even those where we
+ * know they aren't pageable.
+ */
+ if ((fFlags & VBGLR0_HGCMCALL_F_MODE_MASK) == VBGLR0_HGCMCALL_F_USER)
+ rc = RTR0MemObjLockUser(&MemObj, (RTR3PTR)pv, u32Size, fAccess, NIL_RTR0PROCESS);
+ else
+ rc = RTR0MemObjLockKernel(&MemObj, pv, u32Size, fAccess);
+ if (RT_SUCCESS(rc))
+ *ppvCtx = MemObj;
+ else
+ *ppvCtx = NIL_RTR0MEMOBJ;
+
+#endif
+
+ return rc;
+}
+
+void vbglUnlockLinear(void *pvCtx, void *pv, uint32_t u32Size)
+{
+#ifdef RT_OS_WINDOWS
+ PMDL pMdl = (PMDL)pvCtx;
+
+ Assert(pMdl);
+ if (pMdl != NULL)
+ {
+ MmUnlockPages(pMdl);
+ IoFreeMdl(pMdl);
+ }
+
+#else
+ RTR0MEMOBJ MemObj = (RTR0MEMOBJ)pvCtx;
+ int rc = RTR0MemObjFree(MemObj, false);
+ AssertRC(rc);
+
+#endif
+
+ NOREF(pv);
+ NOREF(u32Size);
+}
+
+#else /* !VBGL_VBOXGUEST */
+
+# ifdef RT_OS_OS2
+# include <VBox/VBoxGuest.h> /* for VBOXGUESTOS2IDCCONNECT */
+RT_C_DECLS_BEGIN
+/*
+ * On OS/2 we'll do the connecting in the assembly code of the
+ * client driver, exporting a g_VBoxGuestIDC symbol containing
+ * the connection information obtained from the 16-bit IDC.
+ */
+extern VBOXGUESTOS2IDCCONNECT g_VBoxGuestIDC;
+RT_C_DECLS_END
+# endif
+
+# if !defined(RT_OS_OS2) \
+ && !defined(RT_OS_WINDOWS)
+RT_C_DECLS_BEGIN
+extern DECLVBGL(void *) VBoxGuestIDCOpen(uint32_t *pu32Version);
+extern DECLVBGL(void) VBoxGuestIDCClose(void *pvOpaque);
+extern DECLVBGL(int) VBoxGuestIDCCall(void *pvOpaque, unsigned int iCmd, void *pvData, size_t cbSize, size_t *pcbReturn);
+RT_C_DECLS_END
+# endif
+
+bool vbglDriverIsOpened(VBGLDRIVER *pDriver)
+{
+# ifdef RT_OS_WINDOWS
+ return pDriver->pFileObject != NULL;
+# elif defined (RT_OS_OS2)
+ return pDriver->u32Session != UINT32_MAX && pDriver->u32Session != 0;
+# else
+ return pDriver->pvOpaque != NULL;
+# endif
+}
+
+int vbglDriverOpen(VBGLDRIVER *pDriver)
+{
+# ifdef RT_OS_WINDOWS
+ UNICODE_STRING uszDeviceName;
+ RtlInitUnicodeString(&uszDeviceName, L"\\Device\\VBoxGuest");
+
+ PDEVICE_OBJECT pDeviceObject = NULL;
+ PFILE_OBJECT pFileObject = NULL;
+
+ NTSTATUS rc = IoGetDeviceObjectPointer(&uszDeviceName, FILE_ALL_ACCESS, &pFileObject, &pDeviceObject);
+ if (NT_SUCCESS(rc))
+ {
+ Log(("vbglDriverOpen VBoxGuest successful pDeviceObject=%x\n", pDeviceObject));
+ pDriver->pDeviceObject = pDeviceObject;
+ pDriver->pFileObject = pFileObject;
+ return VINF_SUCCESS;
+ }
+ /** @todo return RTErrConvertFromNtStatus(rc)! */
+ Log(("vbglDriverOpen VBoxGuest failed with ntstatus=%x\n", rc));
+ return rc;
+
+# elif defined (RT_OS_OS2)
+ /*
+ * Just check whether the connection was made or not.
+ */
+ if ( g_VBoxGuestIDC.u32Version == VMMDEV_VERSION
+ && RT_VALID_PTR(g_VBoxGuestIDC.u32Session)
+ && RT_VALID_PTR(g_VBoxGuestIDC.pfnServiceEP))
+ {
+ pDriver->u32Session = g_VBoxGuestIDC.u32Session;
+ return VINF_SUCCESS;
+ }
+ pDriver->u32Session = UINT32_MAX;
+ Log(("vbglDriverOpen: failed\n"));
+ return VERR_FILE_NOT_FOUND;
+
+# else
+ uint32_t u32VMMDevVersion;
+ pDriver->pvOpaque = VBoxGuestIDCOpen(&u32VMMDevVersion);
+ if ( pDriver->pvOpaque
+ && u32VMMDevVersion == VMMDEV_VERSION)
+ return VINF_SUCCESS;
+
+ Log(("vbglDriverOpen: failed\n"));
+ return VERR_FILE_NOT_FOUND;
+# endif
+}
+
+# ifdef RT_OS_WINDOWS
+static NTSTATUS vbglDriverIOCtlCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
+{
+ RT_NOREF2(DeviceObject, Irp);
+ Log(("VBGL completion %x\n", Irp));
+
+ KEVENT *pEvent = (KEVENT *)Context;
+ KeSetEvent(pEvent, IO_NO_INCREMENT, FALSE);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+# endif
+
+int vbglDriverIOCtl(VBGLDRIVER *pDriver, uint32_t u32Function, void *pvData, uint32_t cbData)
+{
+ Log(("vbglDriverIOCtl: pDriver: %p, Func: %x, pvData: %p, cbData: %d\n", pDriver, u32Function, pvData, cbData));
+
+# ifdef RT_OS_WINDOWS
+ KEVENT Event;
+
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ /* Have to use the IoAllocateIRP method because this code is generic and
+ * must work in any thread context.
+ * The IoBuildDeviceIoControlRequest, which was used here, does not work
+ * when APCs are disabled, for example.
+ */
+ PIRP irp = IoAllocateIrp(pDriver->pDeviceObject->StackSize, FALSE);
+
+ Log(("vbglDriverIOCtl: irp %p, IRQL = %d\n", irp, KeGetCurrentIrql()));
+
+ if (irp == NULL)
+ {
+ Log(("vbglDriverIOCtl: IRP allocation failed!\n"));
+ return VERR_NO_MEMORY;
+ }
+
+ /*
+ * Setup the IRP_MJ_DEVICE_CONTROL IRP.
+ */
+
+ PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(irp);
+
+ nextStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
+ nextStack->MinorFunction = 0;
+ nextStack->DeviceObject = pDriver->pDeviceObject;
+ nextStack->Parameters.DeviceIoControl.OutputBufferLength = cbData;
+ nextStack->Parameters.DeviceIoControl.InputBufferLength = cbData;
+ nextStack->Parameters.DeviceIoControl.IoControlCode = u32Function;
+ nextStack->Parameters.DeviceIoControl.Type3InputBuffer = pvData;
+
+ irp->AssociatedIrp.SystemBuffer = pvData; /* Output buffer. */
+ irp->MdlAddress = NULL;
+
+ /* A completion routine is required to signal the Event. */
+ IoSetCompletionRoutine(irp, vbglDriverIOCtlCompletion, &Event, TRUE, TRUE, TRUE);
+
+ NTSTATUS rc = IoCallDriver(pDriver->pDeviceObject, irp);
+
+ if (NT_SUCCESS (rc))
+ {
+ /* Wait the event to be signalled by the completion routine. */
+ KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+
+ rc = irp->IoStatus.Status;
+
+ Log(("vbglDriverIOCtl: wait completed IRQL = %d\n", KeGetCurrentIrql()));
+ }
+
+ IoFreeIrp(irp);
+
+ if (rc != STATUS_SUCCESS)
+ Log(("vbglDriverIOCtl: ntstatus=%x\n", rc));
+
+ if (NT_SUCCESS(rc))
+ return VINF_SUCCESS;
+ if (rc == STATUS_INVALID_PARAMETER)
+ return VERR_INVALID_PARAMETER;
+ if (rc == STATUS_INVALID_BUFFER_SIZE)
+ return VERR_OUT_OF_RANGE;
+ return VERR_VBGL_IOCTL_FAILED;
+
+# elif defined (RT_OS_OS2)
+ if ( pDriver->u32Session
+ && pDriver->u32Session == g_VBoxGuestIDC.u32Session)
+ return g_VBoxGuestIDC.pfnServiceEP(pDriver->u32Session, u32Function, pvData, cbData, NULL);
+
+ Log(("vbglDriverIOCtl: No connection\n"));
+ return VERR_WRONG_ORDER;
+
+# else
+ return VBoxGuestIDCCall(pDriver->pvOpaque, u32Function, pvData, cbData, NULL);
+# endif
+}
+
+void vbglDriverClose(VBGLDRIVER *pDriver)
+{
+# ifdef RT_OS_WINDOWS
+ Log(("vbglDriverClose pDeviceObject=%x\n", pDriver->pDeviceObject));
+ ObDereferenceObject(pDriver->pFileObject);
+ pDriver->pFileObject = NULL;
+ pDriver->pDeviceObject = NULL;
+
+# elif defined (RT_OS_OS2)
+ pDriver->u32Session = 0;
+
+# else
+ VBoxGuestIDCClose(pDriver->pvOpaque);
+ pDriver->pvOpaque = NULL;
+# endif
+}
+
+#endif /* !VBGL_VBOXGUEST */
+
--- /dev/null
+/* $Id: SysHlp.h $ */
+/** @file
+ * VBoxGuestLibR0 - System dependent helpers internal header.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___VBoxGuestLib_SysHlp_h
+#define ___VBoxGuestLib_SysHlp_h
+
+#include <iprt/types.h>
+
+#ifdef RT_OS_WINDOWS
+# undef PAGE_SIZE
+# undef PAGE_SHIFT
+# include <iprt/nt/ntddk.h>
+/* XP DDK #defines ExFreePool to ExFreePoolWithTag. The latter does not exist on NT4, so...
+ * The same for ExAllocatePool.
+ */
+# undef ExAllocatePool
+# undef ExFreePool
+#endif
+
+typedef struct _VBGLDRIVER
+{
+#ifdef RT_OS_WINDOWS
+ PDEVICE_OBJECT pDeviceObject;
+ PFILE_OBJECT pFileObject;
+#elif defined (RT_OS_OS2)
+ uint32_t u32Session; /**< just for sanity checking. */
+#else /* PORTME */
+ void *pvOpaque;
+#endif
+} VBGLDRIVER;
+
+int vbglLockLinear(void **ppvCtx, void *pv, uint32_t cb, bool fWriteAccess, uint32_t fFlags);
+void vbglUnlockLinear(void *pvCtx, void *pv, uint32_t cb);
+
+
+#ifndef VBGL_VBOXGUEST
+
+/**
+ * Open VBoxGuest driver.
+ *
+ * @param pDriver Pointer to the driver structure.
+ *
+ * @return VBox status code
+ */
+int vbglDriverOpen(VBGLDRIVER *pDriver);
+
+/**
+ * Answers whether the VBoxGuest driver is opened
+ *
+ * @param pDriver Pointer to the driver structure.
+ *
+ * @return true - if opened, false - otherwise
+ */
+bool vbglDriverIsOpened(VBGLDRIVER *pDriver);
+
+/**
+ * Call VBoxGuest driver.
+ *
+ * @param pDriver Pointer to the driver structure.
+ * @param u32Function Function code.
+ * @param pvData Pointer to supplied in/out data buffer.
+ * @param cbData Size of data buffer.
+ *
+ * @returns VBox status code
+ */
+int vbglDriverIOCtl(VBGLDRIVER *pDriver, uint32_t u32Function, void *pvData, uint32_t cbData);
+
+/**
+ * Close VBoxGuest driver.
+ *
+ * @param pDriver Pointer to the driver structure.
+ *
+ * @returns VBox status code
+ */
+void vbglDriverClose(VBGLDRIVER *pDriver);
+
+#endif
+
+#endif
+
--- /dev/null
+/* $Id: VBGLInternal.h $ */
+/** @file
+ * VBoxGuestLibR0 - Internal header.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___VBoxGuestLib_VBGLInternal_h
+#define ___VBoxGuestLib_VBGLInternal_h
+
+#include <VBox/VMMDev.h>
+#include <VBox/VBoxGuest.h>
+#include <VBox/VBoxGuestLib.h>
+
+#include <VBox/log.h>
+
+
+#ifdef RT_OS_WINDOWS /** @todo dprintf() -> Log() */
+# if (defined(DEBUG) && !defined(NO_LOGGING)) || defined(LOG_ENABLED)
+# define dprintf(a) RTLogBackdoorPrintf a
+# else
+# define dprintf(a) do {} while (0)
+# endif
+#else
+# define dprintf(a) Log(a)
+#endif
+
+#include "SysHlp.h"
+
+struct _VBGLPHYSHEAPBLOCK;
+typedef struct _VBGLPHYSHEAPBLOCK VBGLPHYSHEAPBLOCK;
+struct _VBGLPHYSHEAPCHUNK;
+typedef struct _VBGLPHYSHEAPCHUNK VBGLPHYSHEAPCHUNK;
+
+#ifndef VBGL_VBOXGUEST
+struct VBGLHGCMHANDLEDATA
+{
+ uint32_t fAllocated;
+ VBGLDRIVER driver;
+};
+#endif
+
+enum VbglLibStatus
+{
+ VbglStatusNotInitialized = 0,
+ VbglStatusInitializing,
+ VbglStatusReady
+};
+
+/**
+ * Global VBGL ring-0 data.
+ * Lives in VbglR0Init.cpp.
+ */
+typedef struct VBGLDATA
+{
+ enum VbglLibStatus status;
+
+ RTIOPORT portVMMDev;
+
+ VMMDevMemory *pVMMDevMemory;
+
+ /**
+ * Physical memory heap data.
+ * @{
+ */
+
+ VBGLPHYSHEAPBLOCK *pFreeBlocksHead;
+ VBGLPHYSHEAPBLOCK *pAllocBlocksHead;
+ VBGLPHYSHEAPCHUNK *pChunkHead;
+
+ RTSEMFASTMUTEX mutexHeap;
+ /** @} */
+
+ /**
+ * The host version data.
+ */
+ VMMDevReqHostVersion hostVersion;
+
+
+#ifndef VBGL_VBOXGUEST
+ /**
+ * Handle for the main driver instance.
+ * @{
+ */
+
+ RTSEMMUTEX mutexDriverInit;
+
+ VBGLDRIVER driver;
+
+ /** @} */
+
+ /**
+ * Fast heap for HGCM handles data.
+ * @{
+ */
+
+ RTSEMFASTMUTEX mutexHGCMHandle;
+
+ struct VBGLHGCMHANDLEDATA aHGCMHandleData[64];
+
+ /** @} */
+#endif
+} VBGLDATA;
+
+
+#ifndef VBGL_DECL_DATA
+extern VBGLDATA g_vbgldata;
+#endif
+
+/**
+ * Internal macro for checking whether we can pass physical page lists to the
+ * host.
+ *
+ * ASSUMES that vbglR0Enter has been called already.
+ *
+ * @param a_fLocked For the windows shared folders workarounds.
+ *
+ * @remarks Disabled the PageList feature for locked memory on Windows,
+ * because a new MDL is created by VBGL to get the page addresses
+ * and the pages from the MDL are marked as dirty when they should not.
+ */
+#if defined(RT_OS_WINDOWS)
+# define VBGLR0_CAN_USE_PHYS_PAGE_LIST(a_fLocked) \
+ ( !(a_fLocked) && (g_vbgldata.hostVersion.features & VMMDEV_HVF_HGCM_PHYS_PAGE_LIST) )
+#else
+# define VBGLR0_CAN_USE_PHYS_PAGE_LIST(a_fLocked) \
+ ( !!(g_vbgldata.hostVersion.features & VMMDEV_HVF_HGCM_PHYS_PAGE_LIST) )
+#endif
+
+int vbglR0Enter (void);
+
+#ifdef VBOX_WITH_HGCM
+# ifndef VBGL_VBOXGUEST
+int vbglR0HGCMInit(void);
+int vbglR0HGCMTerminate(void);
+# endif
+struct VBGLHGCMHANDLEDATA *vbglHGCMHandleAlloc(void);
+void vbglHGCMHandleFree(struct VBGLHGCMHANDLEDATA *pHandle);
+#endif /* VBOX_WITH_HGCM */
+
+#ifndef VBGL_VBOXGUEST
+/**
+ * Get a handle to the main VBoxGuest driver.
+ * @returns VERR_TRY_AGAIN if the main driver has not yet been loaded.
+ */
+int vbglGetDriver(VBGLDRIVER **ppDriver);
+#endif
+
+#endif /* !___VBoxGuestLib_VBGLInternal_h */
+
--- /dev/null
+/* $Id: VBoxGuestLog.h $ */
+/** @file
+ * VBoxGuestLibR0 - Guest Logging facility.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef __VBOXGUESTLOG__H
+#define __VBOXGUESTLOG__H
+
+#ifndef RT_OS_WINDOWS
+# error "Don't include this file."
+#else /* RT_OS_WINDOWS */
+/* Save LOG_ENABLED state, because "VBox/rt/log.h"
+ * may undefine it for IN_RING0 code.
+ */
+# if (defined(DEBUG) && !defined(NO_LOGGING)) || defined(LOG_ENABLED)
+# define __LOG_ENABLED_SAVED__
+# endif
+
+# if (defined(DEBUG) && !defined(NO_LOGGING)) || defined(LOG_ENABLED)
+# ifdef VBOX_GUEST
+# include <VBox/log.h>
+# undef Log
+# define Log(a) RTLogBackdoorPrintf a
+# else
+# define Log(a) DbgPrint a
+# endif
+# else
+# define Log(a)
+# endif
+
+# ifdef __LOG_ENABLED_SAVED__
+# define LOG_ENABLED
+# undef __LOG_ENABLED_SAVED__
+# endif
+
+#endif /* RT_OS_WINDOWS */
+
+#endif /* !__VBOXGUESTLOG__H */
--- /dev/null
+/* $Id: VBoxGuestR0LibSharedFolders.c $ */
+/** @file
+ * VBoxGuestR0LibSharedFolders - Ring 0 Shared Folders calls.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+/* Entire file is ifdef'ed with !VBGL_VBOXGUEST */
+#ifndef VBGL_VBOXGUEST
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_SHARED_FOLDERS
+#include <VBox/VBoxGuestLibSharedFolders.h>
+#include <VBox/log.h>
+#include <iprt/time.h>
+#include <iprt/mem.h>
+#include <iprt/path.h>
+#include <iprt/string.h>
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+#define SHFL_CPARMS_SET_UTF8 0
+#define SHFL_CPARMS_SET_SYMLINKS 0
+
+#define VBOX_INIT_CALL(a, b, c) \
+ LogFunc(("%s, idClient=%d\n", "SHFL_FN_" # b, (c)->idClient)); \
+ (a)->result = VINF_SUCCESS; \
+ (a)->u32ClientID = (c)->idClient; \
+ (a)->u32Function = SHFL_FN_##b; \
+ (a)->cParms = SHFL_CPARMS_##b
+
+
+
+DECLVBGL(int) VbglR0SfInit(void)
+{
+ return VbglInitClient();
+}
+
+DECLVBGL(void) VbglR0SfTerm(void)
+{
+ VbglTerminate();
+}
+
+DECLVBGL(int) VbglR0SfConnect(PVBGLSFCLIENT pClient)
+{
+ int rc;
+ VBoxGuestHGCMConnectInfo data;
+
+ pClient->handle = NULL;
+
+ RT_ZERO(data);
+ data.result = VINF_SUCCESS;
+ data.Loc.type = VMMDevHGCMLoc_LocalHost_Existing;
+#if defined(RT_OS_LINUX)
+ strcpy(data.Loc.u.host.achName, "VBoxSharedFolders");
+#else
+ RTStrCopy(data.Loc.u.host.achName, sizeof(data.Loc.u.host.achName), "VBoxSharedFolders");
+#endif
+
+ rc = VbglHGCMConnect(&pClient->handle, &data);
+/* Log(("VBOXSF: VbglR0SfConnect: VbglHGCMConnect rc = %#x, result = %#x\n", rc, data.result)); */
+ if (RT_SUCCESS(rc))
+ rc = data.result;
+ if (RT_SUCCESS(rc))
+ {
+ pClient->idClient = data.u32ClientID;
+ LogFunc(("idClient=%d\n", pClient->idClient));
+ }
+ return rc;
+}
+
+DECLVBGL(void) VbglR0SfDisconnect(PVBGLSFCLIENT pClient)
+{
+ int rc;
+ VBoxGuestHGCMDisconnectInfo data;
+
+ LogFunc(("u32ClientID=%d\n", pClient->idClient));
+ if (pClient->handle == NULL)
+ return; /* not connected */
+
+ RT_ZERO(data);
+ data.result = VINF_SUCCESS;
+ data.u32ClientID = pClient->idClient;
+
+ rc = VbglHGCMDisconnect(pClient->handle, &data);
+ NOREF(rc);
+/* Log(("VBOXSF: VbglR0SfDisconnect: VbglHGCMDisconnect rc = %#x, result = %#x\n", rc, data.result)); */
+ return;
+}
+
+DECLVBGL(int) VbglR0SfQueryMappings(PVBGLSFCLIENT pClient, SHFLMAPPING paMappings[], uint32_t *pcMappings)
+{
+ int rc;
+ VBoxSFQueryMappings data;
+
+ VBOX_INIT_CALL(&data.callInfo, QUERY_MAPPINGS, pClient);
+
+ data.flags.type = VMMDevHGCMParmType_32bit;
+ data.flags.u.value32 = SHFL_MF_UCS2;
+
+ data.numberOfMappings.type = VMMDevHGCMParmType_32bit;
+ data.numberOfMappings.u.value32 = *pcMappings;
+
+ data.mappings.type = VMMDevHGCMParmType_LinAddr;
+ data.mappings.u.Pointer.size = sizeof(SHFLMAPPING) * *pcMappings;
+ data.mappings.u.Pointer.u.linearAddr = (uintptr_t)&paMappings[0];
+
+/* Log(("VBOXSF: in ifs difference %d\n", (char *)&data.flags.type - (char *)&data.callInfo.cParms)); */
+ rc = VbglHGCMCall(pClient->handle, &data.callInfo, sizeof(data));
+/* Log(("VBOXSF: VbglR0SfQueryMappings: VbglHGCMCall rc = %#x, result = %#x\n", rc, data.callInfo.result)); */
+ if (RT_SUCCESS(rc))
+ rc = data.callInfo.result;
+ if (RT_SUCCESS(rc))
+ *pcMappings = data.numberOfMappings.u.value32;
+
+ return rc;
+}
+
+DECLVBGL(int) VbglR0SfQueryMapName(PVBGLSFCLIENT pClient, SHFLROOT root, SHFLSTRING *pString, uint32_t size)
+{
+ int rc;
+ VBoxSFQueryMapName data;
+
+ VBOX_INIT_CALL(&data.callInfo, QUERY_MAP_NAME, pClient);
+
+ data.root.type = VMMDevHGCMParmType_32bit;
+ data.root.u.value32 = root;
+
+ data.name.type = VMMDevHGCMParmType_LinAddr;
+ data.name.u.Pointer.size = size;
+ data.name.u.Pointer.u.linearAddr = (uintptr_t)pString;
+
+ rc = VbglHGCMCall(pClient->handle, &data.callInfo, sizeof(data));
+/* Log(("VBOXSF: VbglR0SfQueryMapName: VbglHGCMCall rc = %#x, result = %#x\n", rc, data.callInfo.result)); */
+ if (RT_SUCCESS(rc))
+ rc = data.callInfo.result;
+
+ return rc;
+}
+
+DECLVBGL(int) VbglR0SfMapFolder(PVBGLSFCLIENT pClient, PSHFLSTRING szFolderName, PVBGLSFMAP pMap)
+{
+ int rc;
+ VBoxSFMapFolder data;
+
+ VBOX_INIT_CALL(&data.callInfo, MAP_FOLDER, pClient);
+
+ data.path.type = VMMDevHGCMParmType_LinAddr;
+ data.path.u.Pointer.size = ShflStringSizeOfBuffer(szFolderName);
+ data.path.u.Pointer.u.linearAddr = (uintptr_t)szFolderName;
+
+ data.root.type = VMMDevHGCMParmType_32bit;
+ data.root.u.value32 = 0;
+
+ data.delimiter.type = VMMDevHGCMParmType_32bit;
+ data.delimiter.u.value32 = RTPATH_DELIMITER;
+
+ data.fCaseSensitive.type = VMMDevHGCMParmType_32bit;
+#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
+ data.fCaseSensitive.u.value32 = 0;
+#else
+ data.fCaseSensitive.u.value32 = 1;
+#endif
+
+ rc = VbglHGCMCall(pClient->handle, &data.callInfo, sizeof(data));
+/* Log(("VBOXSF: VbglR0SfMapFolder: VbglHGCMCall rc = %#x, result = %#x\n", rc, data.callInfo.result)); */
+ if (RT_SUCCESS(rc))
+ {
+ pMap->root = data.root.u.value32;
+ rc = data.callInfo.result;
+ }
+ else if (rc == VERR_NOT_IMPLEMENTED)
+ {
+ /* try the legacy interface too; temporary to assure backwards compatibility */
+ VBoxSFMapFolder_Old OldData;
+
+ VBOX_INIT_CALL(&OldData.callInfo, MAP_FOLDER_OLD, pClient);
+
+ OldData.path.type = VMMDevHGCMParmType_LinAddr;
+ OldData.path.u.Pointer.size = ShflStringSizeOfBuffer (szFolderName);
+ OldData.path.u.Pointer.u.linearAddr = (uintptr_t)szFolderName;
+
+ OldData.root.type = VMMDevHGCMParmType_32bit;
+ OldData.root.u.value32 = 0;
+
+ OldData.delimiter.type = VMMDevHGCMParmType_32bit;
+ OldData.delimiter.u.value32 = RTPATH_DELIMITER;
+
+ rc = VbglHGCMCall(pClient->handle, &OldData.callInfo, sizeof(OldData));
+ if (RT_SUCCESS(rc))
+ {
+ pMap->root = OldData.root.u.value32;
+ rc = OldData.callInfo.result;
+ }
+ }
+ return rc;
+}
+
+DECLVBGL(int) VbglR0SfUnmapFolder(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap)
+{
+ int rc;
+ VBoxSFUnmapFolder data;
+
+ VBOX_INIT_CALL(&data.callInfo, UNMAP_FOLDER, pClient);
+
+ data.root.type = VMMDevHGCMParmType_32bit;
+ data.root.u.value32 = pMap->root;
+
+ rc = VbglHGCMCall(pClient->handle, &data.callInfo, sizeof(data));
+/* Log(("VBOXSF: VbglR0SfUnmapFolder: VbglHGCMCall rc = %#x, result = %#x\n", rc, data.callInfo.result)); */
+ if (RT_SUCCESS(rc))
+ rc = data.callInfo.result;
+ return rc;
+}
+
+DECLVBGL(int) VbglR0SfCreate(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, PSHFLSTRING pParsedPath, PSHFLCREATEPARMS pCreateParms)
+{
+ /** @todo copy buffers to physical or mapped memory. */
+ int rc;
+ VBoxSFCreate data;
+
+ VBOX_INIT_CALL(&data.callInfo, CREATE, pClient);
+
+ data.root.type = VMMDevHGCMParmType_32bit;
+ data.root.u.value32 = pMap->root;
+
+ data.path.type = VMMDevHGCMParmType_LinAddr;
+ data.path.u.Pointer.size = ShflStringSizeOfBuffer (pParsedPath);
+ data.path.u.Pointer.u.linearAddr = (uintptr_t)pParsedPath;
+
+ data.parms.type = VMMDevHGCMParmType_LinAddr;
+ data.parms.u.Pointer.size = sizeof(SHFLCREATEPARMS);
+ data.parms.u.Pointer.u.linearAddr = (uintptr_t)pCreateParms;
+
+ rc = VbglHGCMCall(pClient->handle, &data.callInfo, sizeof(data));
+/* Log(("VBOXSF: VbglR0SfCreate: VbglHGCMCall rc = %#x, result = %#x\n", rc, data.callInfo.result)); */
+ if (RT_SUCCESS(rc))
+ rc = data.callInfo.result;
+ return rc;
+}
+
+DECLVBGL(int) VbglR0SfClose(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE Handle)
+{
+ int rc;
+ VBoxSFClose data;
+
+ VBOX_INIT_CALL(&data.callInfo, CLOSE, pClient);
+
+ data.root.type = VMMDevHGCMParmType_32bit;
+ data.root.u.value32 = pMap->root;
+
+ data.handle.type = VMMDevHGCMParmType_64bit;
+ data.handle.u.value64 = Handle;
+
+ rc = VbglHGCMCall(pClient->handle, &data.callInfo, sizeof(data));
+/* Log(("VBOXSF: VbglR0SfClose: VbglHGCMCall rc = %#x, result = %#x\n", rc, data.callInfo.result)); */
+ if (RT_SUCCESS(rc))
+ rc = data.callInfo.result;
+ return rc;
+}
+
+DECLVBGL(int) VbglR0SfRemove(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, PSHFLSTRING pParsedPath, uint32_t flags)
+{
+ int rc = VINF_SUCCESS;
+
+ VBoxSFRemove data;
+
+ VBOX_INIT_CALL(&data.callInfo, REMOVE, pClient);
+
+ data.root.type = VMMDevHGCMParmType_32bit;
+ data.root.u.value32 = pMap->root;
+
+ data.path.type = VMMDevHGCMParmType_LinAddr_In;
+ data.path.u.Pointer.size = ShflStringSizeOfBuffer(pParsedPath);
+ data.path.u.Pointer.u.linearAddr = (uintptr_t)pParsedPath;
+
+ data.flags.type = VMMDevHGCMParmType_32bit;
+ data.flags.u.value32 = flags;
+
+ rc = VbglHGCMCall(pClient->handle, &data.callInfo, sizeof(data));
+/* Log(("VBOXSF: VbglR0SfRemove: VbglHGCMCall rc = %#x, result = %#x\n", rc, data.callInfo.result)); */
+ if (RT_SUCCESS (rc))
+ rc = data.callInfo.result;
+ return rc;
+}
+
+DECLVBGL(int) VbglR0SfRename(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, PSHFLSTRING pSrcPath, PSHFLSTRING pDestPath, uint32_t flags)
+{
+ int rc;
+ VBoxSFRename data;
+
+ VBOX_INIT_CALL(&data.callInfo, RENAME, pClient);
+
+ data.root.type = VMMDevHGCMParmType_32bit;
+ data.root.u.value32 = pMap->root;
+
+ data.src.type = VMMDevHGCMParmType_LinAddr_In;
+ data.src.u.Pointer.size = ShflStringSizeOfBuffer(pSrcPath);
+ data.src.u.Pointer.u.linearAddr = (uintptr_t)pSrcPath;
+
+ data.dest.type = VMMDevHGCMParmType_LinAddr_In;
+ data.dest.u.Pointer.size = ShflStringSizeOfBuffer(pDestPath);
+ data.dest.u.Pointer.u.linearAddr = (uintptr_t)pDestPath;
+
+ data.flags.type = VMMDevHGCMParmType_32bit;
+ data.flags.u.value32 = flags;
+
+ rc = VbglHGCMCall(pClient->handle, &data.callInfo, sizeof(data));
+/* Log(("VBOXSF: VbglR0SfRename: VbglHGCMCall rc = %#x, result = %#x\n", rc, data.callInfo.result)); */
+ if (RT_SUCCESS (rc))
+ rc = data.callInfo.result;
+ return rc;
+}
+
+DECLVBGL(int) VbglR0SfRead(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE hFile,
+ uint64_t offset, uint32_t *pcbBuffer, uint8_t *pBuffer, bool fLocked)
+{
+ int rc;
+ VBoxSFRead data;
+
+ VBOX_INIT_CALL(&data.callInfo, READ, pClient);
+
+ data.root.type = VMMDevHGCMParmType_32bit;
+ data.root.u.value32 = pMap->root;
+
+ data.handle.type = VMMDevHGCMParmType_64bit;
+ data.handle.u.value64 = hFile;
+ data.offset.type = VMMDevHGCMParmType_64bit;
+ data.offset.u.value64 = offset;
+ data.cb.type = VMMDevHGCMParmType_32bit;
+ data.cb.u.value32 = *pcbBuffer;
+ data.buffer.type = (fLocked) ? VMMDevHGCMParmType_LinAddr_Locked_Out : VMMDevHGCMParmType_LinAddr_Out;
+ data.buffer.u.Pointer.size = *pcbBuffer;
+ data.buffer.u.Pointer.u.linearAddr = (uintptr_t)pBuffer;
+
+ rc = VbglHGCMCall(pClient->handle, &data.callInfo, sizeof(data));
+/* Log(("VBOXSF: VbglR0SfRead: VbglHGCMCall rc = %#x, result = %#x\n", rc, data.callInfo.result)); */
+ if (RT_SUCCESS(rc))
+ {
+ rc = data.callInfo.result;
+ *pcbBuffer = data.cb.u.value32;
+ }
+ return rc;
+}
+
+DECLVBGL(int) VbglR0SfReadPageList(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE hFile, uint64_t offset, uint32_t *pcbBuffer,
+ uint16_t offFirstPage, uint16_t cPages, RTGCPHYS64 *paPages)
+{
+ uint32_t cbToRead = *pcbBuffer;
+ uint32_t cbData = (uint32_t)(sizeof(VBoxSFRead) + RT_UOFFSETOF(HGCMPageListInfo, aPages[cPages]));
+ VBoxSFRead *pData = (VBoxSFRead *)RTMemTmpAlloc(cbData);
+ HGCMPageListInfo *pPgLst = (HGCMPageListInfo *)(pData + 1);
+ uint16_t iPage;
+ int rc;
+
+ if (RT_UNLIKELY(!pData))
+ return VERR_NO_TMP_MEMORY;
+
+ VBOX_INIT_CALL(&pData->callInfo, READ, pClient);
+
+ pData->root.type = VMMDevHGCMParmType_32bit;
+ pData->root.u.value32 = pMap->root;
+
+ pData->handle.type = VMMDevHGCMParmType_64bit;
+ pData->handle.u.value64 = hFile;
+ pData->offset.type = VMMDevHGCMParmType_64bit;
+ pData->offset.u.value64 = offset;
+ pData->cb.type = VMMDevHGCMParmType_32bit;
+ pData->cb.u.value32 = cbToRead;
+ pData->buffer.type = VMMDevHGCMParmType_PageList;
+ pData->buffer.u.PageList.size = cbToRead;
+ pData->buffer.u.PageList.offset = sizeof(VBoxSFRead);
+
+ pPgLst->flags = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST;
+ pPgLst->offFirstPage = offFirstPage;
+ pPgLst->cPages = cPages;
+ for (iPage = 0; iPage < cPages; iPage++)
+ pPgLst->aPages[iPage] = paPages[iPage];
+
+ rc = VbglHGCMCall(pClient->handle, &pData->callInfo, cbData);
+/* Log(("VBOXSF: VbglR0SfReadPageList: VbglHGCMCall rc = %#x, result = %#x\n", rc, data.callInfo.result)); */
+ if (RT_SUCCESS(rc))
+ {
+ rc = pData->callInfo.result;
+ *pcbBuffer = pData->cb.u.value32;
+ }
+
+ RTMemTmpFree(pData);
+ return rc;
+}
+
+DECLVBGL(int) VbglR0SfWrite(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE hFile,
+ uint64_t offset, uint32_t *pcbBuffer, uint8_t *pBuffer, bool fLocked)
+{
+ int rc;
+ VBoxSFWrite data;
+
+ VBOX_INIT_CALL(&data.callInfo, WRITE, pClient);
+
+ data.root.type = VMMDevHGCMParmType_32bit;
+ data.root.u.value32 = pMap->root;
+
+ data.handle.type = VMMDevHGCMParmType_64bit;
+ data.handle.u.value64 = hFile;
+ data.offset.type = VMMDevHGCMParmType_64bit;
+ data.offset.u.value64 = offset;
+ data.cb.type = VMMDevHGCMParmType_32bit;
+ data.cb.u.value32 = *pcbBuffer;
+ data.buffer.type = fLocked ? VMMDevHGCMParmType_LinAddr_Locked_In : VMMDevHGCMParmType_LinAddr_In;
+ data.buffer.u.Pointer.size = *pcbBuffer;
+ data.buffer.u.Pointer.u.linearAddr = (uintptr_t)pBuffer;
+
+ rc = VbglHGCMCall(pClient->handle, &data.callInfo, sizeof(data));
+/* Log(("VBOXSF: VbglR0SfWrite: VbglHGCMCall rc = %#x, result = %#x\n", rc, data.callInfo.result)); */
+ if (RT_SUCCESS(rc))
+ {
+ rc = data.callInfo.result;
+ *pcbBuffer = data.cb.u.value32;
+ }
+ return rc;
+}
+
+DECLVBGL(int) VbglR0SfWritePhysCont(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE hFile, uint64_t offset,
+ uint32_t *pcbBuffer, RTCCPHYS PhysBuffer)
+{
+ uint32_t cbToWrite = *pcbBuffer;
+ uint32_t cPages = RT_ALIGN_32((PhysBuffer & PAGE_OFFSET_MASK) + cbToWrite, PAGE_SIZE) >> PAGE_SHIFT;
+ uint32_t cbData = (uint32_t)(sizeof(VBoxSFWrite) + RT_UOFFSETOF(HGCMPageListInfo, aPages[cPages]));
+ VBoxSFWrite *pData = (VBoxSFWrite *)RTMemTmpAlloc(cbData);
+ HGCMPageListInfo *pPgLst = (HGCMPageListInfo *)(pData + 1);
+ uint32_t iPage;
+ int rc;
+
+ if (RT_UNLIKELY(!pData))
+ return VERR_NO_TMP_MEMORY;
+
+ VBOX_INIT_CALL(&pData->callInfo, WRITE, pClient);
+
+ pData->root.type = VMMDevHGCMParmType_32bit;
+ pData->root.u.value32 = pMap->root;
+
+ pData->handle.type = VMMDevHGCMParmType_64bit;
+ pData->handle.u.value64 = hFile;
+ pData->offset.type = VMMDevHGCMParmType_64bit;
+ pData->offset.u.value64 = offset;
+ pData->cb.type = VMMDevHGCMParmType_32bit;
+ pData->cb.u.value32 = cbToWrite;
+ pData->buffer.type = VMMDevHGCMParmType_PageList;
+ pData->buffer.u.PageList.size = cbToWrite;
+ pData->buffer.u.PageList.offset = sizeof(VBoxSFWrite);
+
+ pPgLst->flags = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST;
+ pPgLst->offFirstPage = (uint16_t)(PhysBuffer & PAGE_OFFSET_MASK);
+ pPgLst->cPages = cPages;
+ PhysBuffer &= ~(RTCCPHYS)PAGE_OFFSET_MASK;
+ for (iPage = 0; iPage < cPages; iPage++, PhysBuffer += PAGE_SIZE)
+ pPgLst->aPages[iPage] = PhysBuffer;
+
+ rc = VbglHGCMCall(pClient->handle, &pData->callInfo, cbData);
+/* Log(("VBOXSF: VbglR0SfWritePhysCont: VbglHGCMCall rc = %#x, result = %#x\n", rc, data.callInfo.result)); */
+ if (RT_SUCCESS(rc))
+ {
+ rc = pData->callInfo.result;
+ *pcbBuffer = pData->cb.u.value32;
+ }
+
+ RTMemTmpFree(pData);
+ return rc;
+
+}
+
+DECLVBGL(int) VbglR0SfWritePageList(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE hFile, uint64_t offset, uint32_t *pcbBuffer,
+ uint16_t offFirstPage, uint16_t cPages, RTGCPHYS64 *paPages)
+{
+ uint32_t cbToWrite = *pcbBuffer;
+ uint32_t cbData = (uint32_t)(sizeof(VBoxSFWrite) + RT_UOFFSETOF(HGCMPageListInfo, aPages[cPages]));
+ VBoxSFWrite *pData = (VBoxSFWrite *)RTMemTmpAlloc(cbData);
+ HGCMPageListInfo *pPgLst = (HGCMPageListInfo *)(pData + 1);
+ uint16_t iPage;
+ int rc;
+
+ if (RT_UNLIKELY(!pData))
+ return VERR_NO_TMP_MEMORY;
+
+ VBOX_INIT_CALL(&pData->callInfo, WRITE, pClient);
+
+ pData->root.type = VMMDevHGCMParmType_32bit;
+ pData->root.u.value32 = pMap->root;
+
+ pData->handle.type = VMMDevHGCMParmType_64bit;
+ pData->handle.u.value64 = hFile;
+ pData->offset.type = VMMDevHGCMParmType_64bit;
+ pData->offset.u.value64 = offset;
+ pData->cb.type = VMMDevHGCMParmType_32bit;
+ pData->cb.u.value32 = cbToWrite;
+ pData->buffer.type = VMMDevHGCMParmType_PageList;
+ pData->buffer.u.PageList.size = cbToWrite;
+ pData->buffer.u.PageList.offset = sizeof(VBoxSFWrite);
+
+ pPgLst->flags = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST;
+ pPgLst->offFirstPage = offFirstPage;
+ pPgLst->cPages = cPages;
+ for (iPage = 0; iPage < cPages; iPage++)
+ pPgLst->aPages[iPage] = paPages[iPage];
+
+ rc = VbglHGCMCall(pClient->handle, &pData->callInfo, cbData);
+/* Log(("VBOXSF: VbglR0SfWritePageList: VbglHGCMCall rc = %#x, result = %#x\n", rc, data.callInfo.result)); */
+ if (RT_SUCCESS(rc))
+ {
+ rc = pData->callInfo.result;
+ *pcbBuffer = pData->cb.u.value32;
+ }
+
+ RTMemTmpFree(pData);
+ return rc;
+}
+
+DECLVBGL(int) VbglR0SfFlush(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE hFile)
+{
+ int rc;
+ VBoxSFFlush data;
+
+ VBOX_INIT_CALL(&data.callInfo, FLUSH, pClient);
+
+ data.root.type = VMMDevHGCMParmType_32bit;
+ data.root.u.value32 = pMap->root;
+
+ data.handle.type = VMMDevHGCMParmType_64bit;
+ data.handle.u.value64 = hFile;
+
+ rc = VbglHGCMCall(pClient->handle, &data.callInfo, sizeof(data));
+/* Log(("VBOXSF: VbglR0SfFlush: VbglHGCMCall rc = %#x, result = %#x\n", rc, data.callInfo.result)); */
+ if (RT_SUCCESS(rc))
+ rc = data.callInfo.result;
+ return rc;
+}
+
+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)
+{
+ int rc;
+ VBoxSFList data;
+
+ VBOX_INIT_CALL(&data.callInfo, LIST, pClient);
+
+ data.root.type = VMMDevHGCMParmType_32bit;
+ data.root.u.value32 = pMap->root;
+
+ data.handle.type = VMMDevHGCMParmType_64bit;
+ data.handle.u.value64 = hFile;
+ data.flags.type = VMMDevHGCMParmType_32bit;
+ data.flags.u.value32 = flags;
+ data.cb.type = VMMDevHGCMParmType_32bit;
+ data.cb.u.value32 = *pcbBuffer;
+ data.path.type = VMMDevHGCMParmType_LinAddr_In;
+ data.path.u.Pointer.size = ParsedPath ? ShflStringSizeOfBuffer(ParsedPath) : 0;
+ data.path.u.Pointer.u.linearAddr = (uintptr_t) ParsedPath;
+
+ data.buffer.type = VMMDevHGCMParmType_LinAddr_Out;
+ data.buffer.u.Pointer.size = *pcbBuffer;
+ data.buffer.u.Pointer.u.linearAddr = (uintptr_t)pBuffer;
+
+ data.resumePoint.type = VMMDevHGCMParmType_32bit;
+ data.resumePoint.u.value32 = index;
+ data.cFiles.type = VMMDevHGCMParmType_32bit;
+ data.cFiles.u.value32 = 0; /* out parameters only */
+
+ rc = VbglHGCMCall(pClient->handle, &data.callInfo, sizeof(data));
+/* Log(("VBOXSF: VbglR0SfDirInfo: rc = %#x, result = %#x\n", rc, data.callInfo.result)); */
+ if (RT_SUCCESS(rc))
+ rc = data.callInfo.result;
+ *pcbBuffer = data.cb.u.value32;
+ *pcFiles = data.cFiles.u.value32;
+ return rc;
+}
+
+DECLVBGL(int) VbglR0SfFsInfo(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE hFile,
+ uint32_t flags, uint32_t *pcbBuffer, PSHFLDIRINFO pBuffer)
+{
+ int rc;
+ VBoxSFInformation data;
+
+ VBOX_INIT_CALL(&data.callInfo, INFORMATION, pClient);
+
+ data.root.type = VMMDevHGCMParmType_32bit;
+ data.root.u.value32 = pMap->root;
+
+ data.handle.type = VMMDevHGCMParmType_64bit;
+ data.handle.u.value64 = hFile;
+ data.flags.type = VMMDevHGCMParmType_32bit;
+ data.flags.u.value32 = flags;
+ data.cb.type = VMMDevHGCMParmType_32bit;
+ data.cb.u.value32 = *pcbBuffer;
+ data.info.type = VMMDevHGCMParmType_LinAddr;
+ data.info.u.Pointer.size = *pcbBuffer;
+ data.info.u.Pointer.u.linearAddr = (uintptr_t)pBuffer;
+
+ rc = VbglHGCMCall(pClient->handle, &data.callInfo, sizeof(data));
+/* Log(("VBOXSF: VbglR0SfFsInfo: VbglHGCMCall rc = %#x, result = %#x\n", rc, data.callInfo.result)); */
+ if (RT_SUCCESS(rc))
+ {
+ rc = data.callInfo.result;
+ *pcbBuffer = data.cb.u.value32;
+ }
+ return rc;
+}
+
+DECLVBGL(int) VbglR0SfLock(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE hFile,
+ uint64_t offset, uint64_t cbSize, uint32_t fLock)
+{
+ int rc;
+ VBoxSFLock data;
+
+ VBOX_INIT_CALL(&data.callInfo, LOCK, pClient);
+
+ data.root.type = VMMDevHGCMParmType_32bit;
+ data.root.u.value32 = pMap->root;
+
+ data.handle.type = VMMDevHGCMParmType_64bit;
+ data.handle.u.value64 = hFile;
+ data.offset.type = VMMDevHGCMParmType_64bit;
+ data.offset.u.value64 = offset;
+ data.length.type = VMMDevHGCMParmType_64bit;
+ data.length.u.value64 = cbSize;
+
+ data.flags.type = VMMDevHGCMParmType_32bit;
+ data.flags.u.value32 = fLock;
+
+ rc = VbglHGCMCall(pClient->handle, &data.callInfo, sizeof(data));
+/* Log(("VBOXSF: VbglR0SfLock: VbglHGCMCall rc = %#x, result = %#x\n", rc, data.callInfo.result)); */
+ if (RT_SUCCESS (rc))
+ rc = data.callInfo.result;
+ return rc;
+}
+
+DECLVBGL(int) VbglR0SfSetUtf8(PVBGLSFCLIENT pClient)
+{
+ int rc;
+ VBoxGuestHGCMCallInfo callInfo;
+
+ VBOX_INIT_CALL(&callInfo, SET_UTF8, pClient);
+ rc = VbglHGCMCall(pClient->handle, &callInfo, sizeof(callInfo));
+/* Log(("VBOXSF: VbglR0SfSetUtf8: VbglHGCMCall rc = %#x, result = %#x\n", rc, data.callInfo.result)); */
+ if (RT_SUCCESS(rc))
+ rc = callInfo.result;
+ return rc;
+}
+
+DECLVBGL(int) VbglR0SfReadLink(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, PSHFLSTRING pParsedPath, uint32_t cbBuffer, uint8_t *pBuffer)
+{
+ int rc;
+ VBoxSFReadLink data;
+
+ VBOX_INIT_CALL(&data.callInfo, READLINK, pClient);
+
+ data.root.type = VMMDevHGCMParmType_32bit;
+ data.root.u.value32 = pMap->root;
+
+ data.path.type = VMMDevHGCMParmType_LinAddr_In;
+ data.path.u.Pointer.size = ShflStringSizeOfBuffer (pParsedPath);
+ data.path.u.Pointer.u.linearAddr = (uintptr_t)pParsedPath;
+
+ data.buffer.type = VMMDevHGCMParmType_LinAddr_Out;
+ data.buffer.u.Pointer.size = cbBuffer;
+ data.buffer.u.Pointer.u.linearAddr = (uintptr_t)pBuffer;
+
+ rc = VbglHGCMCall(pClient->handle, &data.callInfo, sizeof(data));
+/* Log(("VBOXSF: VbglR0SfReadLink: VbglHGCMCall rc = %#x, result = %#x\n", rc, data.callInfo.result)); */
+ if (RT_SUCCESS (rc))
+ rc = data.callInfo.result;
+ return rc;
+}
+
+DECLVBGL(int) VbglR0SfSymlink(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, PSHFLSTRING pNewPath, PSHFLSTRING pOldPath,
+ PSHFLFSOBJINFO pBuffer)
+{
+ int rc;
+ VBoxSFSymlink data;
+
+ VBOX_INIT_CALL(&data.callInfo, SYMLINK, pClient);
+
+ data.root.type = VMMDevHGCMParmType_32bit;
+ data.root.u.value32 = pMap->root;
+
+ data.newPath.type = VMMDevHGCMParmType_LinAddr_In;
+ data.newPath.u.Pointer.size = ShflStringSizeOfBuffer (pNewPath);
+ data.newPath.u.Pointer.u.linearAddr = (uintptr_t)pNewPath;
+
+ data.oldPath.type = VMMDevHGCMParmType_LinAddr_In;
+ data.oldPath.u.Pointer.size = ShflStringSizeOfBuffer (pOldPath);
+ data.oldPath.u.Pointer.u.linearAddr = (uintptr_t)pOldPath;
+
+ data.info.type = VMMDevHGCMParmType_LinAddr_Out;
+ data.info.u.Pointer.size = sizeof(SHFLFSOBJINFO);
+ data.info.u.Pointer.u.linearAddr = (uintptr_t)pBuffer;
+
+ rc = VbglHGCMCall(pClient->handle, &data.callInfo, sizeof(data));
+/* Log(("VBOXSF: VbglR0SfSymlink: VbglHGCMCall rc = %#x, result = %#x\n", rc, data.callInfo.result)); */
+ if (RT_SUCCESS (rc))
+ rc = data.callInfo.result;
+ return rc;
+}
+
+DECLVBGL(int) VbglR0SfSetSymlinks(PVBGLSFCLIENT pClient)
+{
+ int rc;
+ VBoxGuestHGCMCallInfo callInfo;
+
+ VBOX_INIT_CALL(&callInfo, SET_SYMLINKS, pClient);
+ rc = VbglHGCMCall(pClient->handle, &callInfo, sizeof(callInfo));
+/* Log(("VBOXSF: VbglR0SfSetSymlinks: VbglHGCMCall rc = %#x, result = %#x\n", rc, data.callInfo.result)); */
+ if (RT_SUCCESS(rc))
+ rc = callInfo.result;
+ return rc;
+}
+
+
+#endif /* !VBGL_VBOXGUEST */
--- /dev/null
+/* $Id: VMMDev.cpp $ */
+/** @file
+ * VBoxGuestLibR0 - VMMDev device related functions.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#include "VBGLInternal.h"
+
+
+DECLVBGL(int) VbglQueryVMMDevMemory(VMMDevMemory **ppVMMDevMemory)
+{
+ int rc = vbglR0Enter();
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* If the memory was not found, return an error. */
+ if (!g_vbgldata.pVMMDevMemory)
+ return VERR_NOT_SUPPORTED;
+
+ *ppVMMDevMemory = g_vbgldata.pVMMDevMemory;
+ return rc;
+}
+
--- /dev/null
+/* $Id: VbglR0CanUsePhysPageList.cpp $ */
+/** @file
+ * VBoxGuestLibR0 - Physical memory heap.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#include "VBGLInternal.h"
+
+
+/**
+ * Checks whether the host supports physical page lists or not.
+ *
+ * @returns true if it does, false if it doesn't.
+ */
+DECLR0VBGL(bool) VbglR0CanUsePhysPageList(void)
+{
+ /* a_fLocked is false, because the actual capability of the host is requested.
+ * See VBGLR0_CAN_USE_PHYS_PAGE_LIST definition.
+ */
+ int rc = vbglR0Enter();
+ return RT_SUCCESS(rc)
+ && VBGLR0_CAN_USE_PHYS_PAGE_LIST(/*a_fLocked =*/ false);
+}
+
--- /dev/null
+/** @file
+ *
+ * vboxsf -- VirtualBox Guest Additions for Linux:
+ * Directory inode and file operations
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "vfsmod.h"
+
+/**
+ * Open a directory. Read the complete content into a buffer.
+ *
+ * @param inode inode
+ * @param file file
+ * @returns 0 on success, Linux error code otherwise
+ */
+static int sf_dir_open(struct inode *inode, struct file *file)
+{
+ int rc;
+ int err;
+ struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
+ struct sf_dir_info *sf_d;
+ struct sf_inode_info *sf_i = GET_INODE_INFO(inode);
+ SHFLCREATEPARMS params;
+
+ TRACE();
+ BUG_ON(!sf_g);
+ BUG_ON(!sf_i);
+
+ if (file->private_data)
+ {
+ LogFunc(("sf_dir_open() called on already opened directory '%s'\n",
+ sf_i->path->String.utf8));
+ return 0;
+ }
+
+ sf_d = sf_dir_info_alloc();
+ if (!sf_d)
+ {
+ LogRelFunc(("could not allocate directory info for '%s'\n",
+ sf_i->path->String.utf8));
+ return -ENOMEM;
+ }
+
+ RT_ZERO(params);
+ params.Handle = SHFL_HANDLE_NIL;
+ params.CreateFlags = 0
+ | SHFL_CF_DIRECTORY
+ | SHFL_CF_ACT_OPEN_IF_EXISTS
+ | SHFL_CF_ACT_FAIL_IF_NEW
+ | SHFL_CF_ACCESS_READ
+ ;
+
+ LogFunc(("sf_dir_open(): calling VbglR0SfCreate, folder %s, flags %#x\n",
+ sf_i->path->String.utf8, params.CreateFlags));
+ rc = VbglR0SfCreate(&client_handle, &sf_g->map, sf_i->path, ¶ms);
+ if (RT_SUCCESS(rc))
+ {
+ if (params.Result == SHFL_FILE_EXISTS)
+ {
+ err = sf_dir_read_all(sf_g, sf_i, sf_d, params.Handle);
+ if (!err)
+ file->private_data = sf_d;
+ }
+ else
+ err = -ENOENT;
+
+ rc = VbglR0SfClose(&client_handle, &sf_g->map, params.Handle);
+ if (RT_FAILURE(rc))
+ LogFunc(("sf_dir_open(): VbglR0SfClose(%s) after err=%d failed rc=%Rrc\n",
+ sf_i->path->String.utf8, err, rc));
+ }
+ else
+ err = -EPERM;
+
+ if (err)
+ sf_dir_info_free(sf_d);
+
+ return err;
+}
+
+
+/**
+ * This is called when reference count of [file] goes to zero. Notify
+ * the host that it can free whatever is associated with this directory
+ * and deallocate our own internal buffers
+ *
+ * @param inode inode
+ * @param file file
+ * returns 0 on success, Linux error code otherwise
+ */
+static int sf_dir_release(struct inode *inode, struct file *file)
+{
+ TRACE();
+
+ if (file->private_data)
+ sf_dir_info_free(file->private_data);
+
+ return 0;
+}
+
+/**
+ * Translate RTFMODE into DT_xxx (in conjunction to rtDirType())
+ * @param fMode file mode
+ * returns d_type
+ */
+static int sf_get_d_type(RTFMODE fMode)
+{
+ int d_type;
+ switch (fMode & RTFS_TYPE_MASK)
+ {
+ case RTFS_TYPE_FIFO: d_type = DT_FIFO; break;
+ case RTFS_TYPE_DEV_CHAR: d_type = DT_CHR; break;
+ case RTFS_TYPE_DIRECTORY: d_type = DT_DIR; break;
+ case RTFS_TYPE_DEV_BLOCK: d_type = DT_BLK; break;
+ case RTFS_TYPE_FILE: d_type = DT_REG; break;
+ case RTFS_TYPE_SYMLINK: d_type = DT_LNK; break;
+ case RTFS_TYPE_SOCKET: d_type = DT_SOCK; break;
+ case RTFS_TYPE_WHITEOUT: d_type = DT_WHT; break;
+ default: d_type = DT_UNKNOWN; break;
+ }
+ return d_type;
+}
+
+/**
+ * Extract element ([dir]->f_pos) from the directory [dir] into [d_name].
+ *
+ * @returns 0 for success, 1 for end reached, Linux error code otherwise.
+ */
+static int sf_getdent(struct file *dir, char d_name[NAME_MAX], int *d_type)
+{
+ loff_t cur;
+ struct sf_glob_info *sf_g;
+ struct sf_dir_info *sf_d;
+ struct sf_inode_info *sf_i;
+ struct inode *inode;
+ struct list_head *pos, *list;
+
+ TRACE();
+
+ inode = GET_F_DENTRY(dir)->d_inode;
+ sf_i = GET_INODE_INFO(inode);
+ sf_g = GET_GLOB_INFO(inode->i_sb);
+ sf_d = dir->private_data;
+
+ BUG_ON(!sf_g);
+ BUG_ON(!sf_d);
+ BUG_ON(!sf_i);
+
+ if (sf_i->force_reread)
+ {
+ int rc;
+ int err;
+ SHFLCREATEPARMS params;
+
+ RT_ZERO(params);
+ params.Handle = SHFL_HANDLE_NIL;
+ params.CreateFlags = 0
+ | SHFL_CF_DIRECTORY
+ | SHFL_CF_ACT_OPEN_IF_EXISTS
+ | SHFL_CF_ACT_FAIL_IF_NEW
+ | SHFL_CF_ACCESS_READ
+ ;
+
+ LogFunc(("sf_getdent: calling VbglR0SfCreate, folder %s, flags %#x\n",
+ sf_i->path->String.utf8, params.CreateFlags));
+ rc = VbglR0SfCreate(&client_handle, &sf_g->map, sf_i->path, ¶ms);
+ if (RT_FAILURE(rc))
+ {
+ LogFunc(("VbglR0SfCreate(%s) failed rc=%Rrc\n",
+ sf_i->path->String.utf8, rc));
+ return -EPERM;
+ }
+
+ if (params.Result != SHFL_FILE_EXISTS)
+ {
+ LogFunc(("directory %s does not exist\n", sf_i->path->String.utf8));
+ sf_dir_info_free(sf_d);
+ return -ENOENT;
+ }
+
+ sf_dir_info_empty(sf_d);
+ err = sf_dir_read_all(sf_g, sf_i, sf_d, params.Handle);
+ rc = VbglR0SfClose(&client_handle, &sf_g->map, params.Handle);
+ if (RT_FAILURE(rc))
+ LogFunc(("VbglR0SfClose(%s) failed rc=%Rrc\n", sf_i->path->String.utf8, rc));
+ if (err)
+ return err;
+
+ sf_i->force_reread = 0;
+ }
+
+ cur = 0;
+ list = &sf_d->info_list;
+ list_for_each(pos, list)
+ {
+ struct sf_dir_buf *b;
+ SHFLDIRINFO *info;
+ loff_t i;
+
+ b = list_entry(pos, struct sf_dir_buf, head);
+ if (dir->f_pos >= cur + b->cEntries)
+ {
+ cur += b->cEntries;
+ continue;
+ }
+
+ for (i = 0, info = b->buf; i < dir->f_pos - cur; ++i)
+ {
+ size_t size;
+
+ size = offsetof(SHFLDIRINFO, name.String) + info->name.u16Size;
+ info = (SHFLDIRINFO *) ((uintptr_t) info + size);
+ }
+
+ *d_type = sf_get_d_type(info->Info.Attr.fMode);
+
+ return sf_nlscpy(sf_g, d_name, NAME_MAX,
+ info->name.String.utf8, info->name.u16Length);
+ }
+
+ return 1;
+}
+
+/**
+ * This is called when vfs wants to populate internal buffers with
+ * directory [dir]s contents. [opaque] is an argument to the
+ * [filldir]. [filldir] magically modifies it's argument - [opaque]
+ * and takes following additional arguments (which i in turn get from
+ * the host via sf_getdent):
+ *
+ * name : name of the entry (i must also supply it's length huh?)
+ * type : type of the entry (FILE | DIR | etc) (i ellect to use DT_UNKNOWN)
+ * pos : position/index of the entry
+ * ino : inode number of the entry (i fake those)
+ *
+ * [dir] contains:
+ * f_pos : cursor into the directory listing
+ * private_data : mean of communication with the host side
+ *
+ * Extract elements from the directory listing (incrementing f_pos
+ * along the way) and feed them to [filldir] until:
+ *
+ * a. there are no more entries (i.e. sf_getdent set done to 1)
+ * b. failure to compute fake inode number
+ * c. filldir returns an error (see comment on that)
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
+static int sf_dir_iterate(struct file *dir, struct dir_context *ctx)
+#else
+static int sf_dir_read(struct file *dir, void *opaque, filldir_t filldir)
+#endif
+{
+ TRACE();
+ for (;;)
+ {
+ int err;
+ ino_t fake_ino;
+ loff_t sanity;
+ char d_name[NAME_MAX];
+ int d_type = DT_UNKNOWN;
+
+ err = sf_getdent(dir, d_name, &d_type);
+ switch (err)
+ {
+ case 1:
+ return 0;
+
+ case 0:
+ break;
+
+ case -1:
+ default:
+ /* skip erroneous entry and proceed */
+ LogFunc(("sf_getdent error %d\n", err));
+ dir->f_pos += 1;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
+ ctx->pos += 1;
+#endif
+ continue;
+ }
+
+ /* d_name now contains a valid entry name */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
+ sanity = ctx->pos + 0xbeef;
+#else
+ sanity = dir->f_pos + 0xbeef;
+#endif
+ fake_ino = sanity;
+ if (sanity - fake_ino)
+ {
+ LogRelFunc(("can not compute ino\n"));
+ return -EINVAL;
+ }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
+ if (!dir_emit(ctx, d_name, strlen(d_name), fake_ino, d_type))
+ {
+ LogFunc(("dir_emit failed\n"));
+ return 0;
+ }
+#else
+ err = filldir(opaque, d_name, strlen(d_name), dir->f_pos, fake_ino, d_type);
+ if (err)
+ {
+ LogFunc(("filldir returned error %d\n", err));
+ /* Rely on the fact that filldir returns error
+ only when it runs out of space in opaque */
+ return 0;
+ }
+#endif
+
+ dir->f_pos += 1;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
+ ctx->pos += 1;
+#endif
+ }
+
+ BUG();
+}
+
+struct file_operations sf_dir_fops =
+{
+ .open = sf_dir_open,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
+ .iterate = sf_dir_iterate,
+#else
+ .readdir = sf_dir_read,
+#endif
+ .release = sf_dir_release,
+ .read = generic_read_dir
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
+ , .llseek = generic_file_llseek
+#endif
+};
+
+
+/* iops */
+
+/**
+ * This is called when vfs failed to locate dentry in the cache. The
+ * job of this function is to allocate inode and link it to dentry.
+ * [dentry] contains the name to be looked in the [parent] directory.
+ * Failure to locate the name is not a "hard" error, in this case NULL
+ * inode is added to [dentry] and vfs should proceed trying to create
+ * the entry via other means. NULL(or "positive" pointer) ought to be
+ * returned in case of success and "negative" pointer on error
+ */
+static struct dentry *sf_lookup(struct inode *parent, struct dentry *dentry
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+ , unsigned int flags
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+ , struct nameidata *nd
+#endif
+ )
+{
+ int err;
+ struct sf_inode_info *sf_i, *sf_new_i;
+ struct sf_glob_info *sf_g;
+ SHFLSTRING *path;
+ struct inode *inode;
+ ino_t ino;
+ SHFLFSOBJINFO fsinfo;
+
+ TRACE();
+ sf_g = GET_GLOB_INFO(parent->i_sb);
+ sf_i = GET_INODE_INFO(parent);
+
+ BUG_ON(!sf_g);
+ BUG_ON(!sf_i);
+
+ err = sf_path_from_dentry(__func__, sf_g, sf_i, dentry, &path);
+ if (err)
+ goto fail0;
+
+ err = sf_stat(__func__, sf_g, path, &fsinfo, 1);
+ if (err)
+ {
+ if (err == -ENOENT)
+ {
+ /* -ENOENT: add NULL inode to dentry so it later can be
+ created via call to create/mkdir/open */
+ kfree(path);
+ inode = NULL;
+ }
+ else
+ goto fail1;
+ }
+ else
+ {
+ sf_new_i = kmalloc(sizeof(*sf_new_i), GFP_KERNEL);
+ if (!sf_new_i)
+ {
+ LogRelFunc(("could not allocate memory for new inode info\n"));
+ err = -ENOMEM;
+ goto fail1;
+ }
+ sf_new_i->handle = SHFL_HANDLE_NIL;
+ sf_new_i->force_reread = 0;
+
+ ino = iunique(parent->i_sb, 1);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
+ inode = iget_locked(parent->i_sb, ino);
+#else
+ inode = iget(parent->i_sb, ino);
+#endif
+ if (!inode)
+ {
+ LogFunc(("iget failed\n"));
+ err = -ENOMEM; /* XXX: ??? */
+ goto fail2;
+ }
+
+ SET_INODE_INFO(inode, sf_new_i);
+ sf_init_inode(sf_g, inode, &fsinfo);
+ sf_new_i->path = path;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
+ unlock_new_inode(inode);
+#endif
+ }
+
+ sf_i->force_restat = 0;
+ dentry->d_time = jiffies;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
+ d_set_d_op(dentry, &sf_dentry_ops);
+#else
+ dentry->d_op = &sf_dentry_ops;
+#endif
+ d_add(dentry, inode);
+ return NULL;
+
+fail2:
+ kfree(sf_new_i);
+
+fail1:
+ kfree(path);
+
+fail0:
+ return ERR_PTR(err);
+}
+
+/**
+ * This should allocate memory for sf_inode_info, compute a unique inode
+ * number, get an inode from vfs, initialize inode info, instantiate
+ * dentry.
+ *
+ * @param parent inode entry of the directory
+ * @param dentry directory cache entry
+ * @param path path name
+ * @param info file information
+ * @param handle handle
+ * @returns 0 on success, Linux error code otherwise
+ */
+static int sf_instantiate(struct inode *parent, struct dentry *dentry,
+ SHFLSTRING *path, PSHFLFSOBJINFO info, SHFLHANDLE handle)
+{
+ int err;
+ ino_t ino;
+ struct inode *inode;
+ struct sf_inode_info *sf_new_i;
+ struct sf_glob_info *sf_g = GET_GLOB_INFO(parent->i_sb);
+
+ TRACE();
+ BUG_ON(!sf_g);
+
+ sf_new_i = kmalloc(sizeof(*sf_new_i), GFP_KERNEL);
+ if (!sf_new_i)
+ {
+ LogRelFunc(("could not allocate inode info.\n"));
+ err = -ENOMEM;
+ goto fail0;
+ }
+
+ ino = iunique(parent->i_sb, 1);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
+ inode = iget_locked(parent->i_sb, ino);
+#else
+ inode = iget(parent->i_sb, ino);
+#endif
+ if (!inode)
+ {
+ LogFunc(("iget failed\n"));
+ err = -ENOMEM;
+ goto fail1;
+ }
+
+ sf_init_inode(sf_g, inode, info);
+ sf_new_i->path = path;
+ SET_INODE_INFO(inode, sf_new_i);
+ sf_new_i->force_restat = 1;
+ sf_new_i->force_reread = 0;
+
+ d_instantiate(dentry, inode);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
+ unlock_new_inode(inode);
+#endif
+
+ /* Store this handle if we leave the handle open. */
+ sf_new_i->handle = handle;
+ return 0;
+
+fail1:
+ kfree(sf_new_i);
+
+fail0:
+ return err;
+
+}
+
+/**
+ * Create a new regular file / directory.
+ *
+ * @param parent inode of the directory
+ * @param dentry directory cache entry
+ * @param mode file mode
+ * @param fDirectory true if directory, false otherwise
+ * @returns 0 on success, Linux error code otherwise
+ */
+static int sf_create_aux(struct inode *parent, struct dentry *dentry,
+ umode_t mode, int fDirectory)
+{
+ int rc, err;
+ SHFLCREATEPARMS params;
+ SHFLSTRING *path;
+ struct sf_inode_info *sf_i = GET_INODE_INFO(parent);
+ struct sf_glob_info *sf_g = GET_GLOB_INFO(parent->i_sb);
+
+ TRACE();
+ BUG_ON(!sf_i);
+ BUG_ON(!sf_g);
+
+ err = sf_path_from_dentry(__func__, sf_g, sf_i, dentry, &path);
+ if (err)
+ goto fail0;
+
+ RT_ZERO(params);
+ params.Handle = SHFL_HANDLE_NIL;
+ params.CreateFlags = 0
+ | SHFL_CF_ACT_CREATE_IF_NEW
+ | SHFL_CF_ACT_FAIL_IF_EXISTS
+ | SHFL_CF_ACCESS_READWRITE
+ | (fDirectory ? SHFL_CF_DIRECTORY : 0)
+ ;
+ params.Info.Attr.fMode = 0
+ | (fDirectory ? RTFS_TYPE_DIRECTORY : RTFS_TYPE_FILE)
+ | (mode & S_IRWXUGO)
+ ;
+ params.Info.Attr.enmAdditional = RTFSOBJATTRADD_NOTHING;
+
+ LogFunc(("sf_create_aux: calling VbglR0SfCreate, folder %s, flags %#x\n",
+ path->String.utf8, params.CreateFlags));
+ rc = VbglR0SfCreate(&client_handle, &sf_g->map, path, ¶ms);
+ if (RT_FAILURE(rc))
+ {
+ if (rc == VERR_WRITE_PROTECT)
+ {
+ err = -EROFS;
+ goto fail1;
+ }
+ err = -EPROTO;
+ LogFunc(("(%d): VbglR0SfCreate(%s) failed rc=%Rrc\n",
+ fDirectory, sf_i->path->String.utf8, rc));
+ goto fail1;
+ }
+
+ if (params.Result != SHFL_FILE_CREATED)
+ {
+ err = -EPERM;
+ LogFunc(("(%d): could not create file %s result=%d\n",
+ fDirectory, sf_i->path->String.utf8, params.Result));
+ goto fail1;
+ }
+
+ err = sf_instantiate(parent, dentry, path, ¶ms.Info,
+ fDirectory ? SHFL_HANDLE_NIL : params.Handle);
+ if (err)
+ {
+ LogFunc(("(%d): could not instantiate dentry for %s err=%d\n",
+ fDirectory, sf_i->path->String.utf8, err));
+ goto fail2;
+ }
+
+ /*
+ * Don't close this handle right now. We assume that the same file is
+ * opened with sf_reg_open() and later closed with sf_reg_close(). Save
+ * the handle in between. Does not apply to directories. True?
+ */
+ if (fDirectory)
+ {
+ rc = VbglR0SfClose(&client_handle, &sf_g->map, params.Handle);
+ if (RT_FAILURE(rc))
+ LogFunc(("(%d): VbglR0SfClose failed rc=%Rrc\n", fDirectory, rc));
+ }
+
+ sf_i->force_restat = 1;
+ return 0;
+
+fail2:
+ rc = VbglR0SfClose(&client_handle, &sf_g->map, params.Handle);
+ if (RT_FAILURE(rc))
+ LogFunc(("(%d): VbglR0SfClose failed rc=%Rrc\n", fDirectory, rc));
+
+fail1:
+ kfree(path);
+
+fail0:
+ return err;
+}
+
+/**
+ * Create a new regular file.
+ *
+ * @param parent inode of the directory
+ * @param dentry directory cache entry
+ * @param mode file mode
+ * @param excl Possible O_EXCL...
+ * @returns 0 on success, Linux error code otherwise
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) || defined(DOXYGEN_RUNNING)
+static int sf_create(struct inode *parent, struct dentry *dentry, umode_t mode, bool excl)
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
+static int sf_create(struct inode *parent, struct dentry *dentry, umode_t mode, struct nameidata *nd)
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+static int sf_create(struct inode *parent, struct dentry *dentry, int mode, struct nameidata *nd)
+#else
+static int sf_create(struct inode *parent, struct dentry *dentry, int mode)
+#endif
+{
+ TRACE();
+ return sf_create_aux(parent, dentry, mode, 0);
+}
+
+/**
+ * Create a new directory.
+ *
+ * @param parent inode of the directory
+ * @param dentry directory cache entry
+ * @param mode file mode
+ * @returns 0 on success, Linux error code otherwise
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
+static int sf_mkdir(struct inode *parent, struct dentry *dentry, umode_t mode)
+#else
+static int sf_mkdir(struct inode *parent, struct dentry *dentry, int mode)
+#endif
+{
+ TRACE();
+ return sf_create_aux(parent, dentry, mode, 1);
+}
+
+/**
+ * Remove a regular file / directory.
+ *
+ * @param parent inode of the directory
+ * @param dentry directory cache entry
+ * @param fDirectory true if directory, false otherwise
+ * @returns 0 on success, Linux error code otherwise
+ */
+static int sf_unlink_aux(struct inode *parent, struct dentry *dentry, int fDirectory)
+{
+ int rc, err;
+ struct sf_glob_info *sf_g = GET_GLOB_INFO(parent->i_sb);
+ struct sf_inode_info *sf_i = GET_INODE_INFO(parent);
+ SHFLSTRING *path;
+ uint32_t fFlags;
+
+ TRACE();
+ BUG_ON(!sf_g);
+
+ err = sf_path_from_dentry(__func__, sf_g, sf_i, dentry, &path);
+ if (err)
+ goto fail0;
+
+ fFlags = fDirectory ? SHFL_REMOVE_DIR : SHFL_REMOVE_FILE;
+ if ( dentry
+ && dentry->d_inode
+ && ((dentry->d_inode->i_mode & S_IFLNK) == S_IFLNK))
+ fFlags |= SHFL_REMOVE_SYMLINK;
+ rc = VbglR0SfRemove(&client_handle, &sf_g->map, path, fFlags);
+ if (RT_FAILURE(rc))
+ {
+ LogFunc(("(%d): VbglR0SfRemove(%s) failed rc=%Rrc\n", fDirectory, path->String.utf8, rc));
+ err = -RTErrConvertToErrno(rc);
+ goto fail1;
+ }
+
+ /* directory access/change time changed */
+ sf_i->force_restat = 1;
+ /* directory content changed */
+ sf_i->force_reread = 1;
+
+ err = 0;
+
+fail1:
+ kfree(path);
+
+fail0:
+ return err;
+}
+
+/**
+ * Remove a regular file.
+ *
+ * @param parent inode of the directory
+ * @param dentry directory cache entry
+ * @returns 0 on success, Linux error code otherwise
+ */
+static int sf_unlink(struct inode *parent, struct dentry *dentry)
+{
+ TRACE();
+ return sf_unlink_aux(parent, dentry, 0);
+}
+
+/**
+ * Remove a directory.
+ *
+ * @param parent inode of the directory
+ * @param dentry directory cache entry
+ * @returns 0 on success, Linux error code otherwise
+ */
+static int sf_rmdir(struct inode *parent, struct dentry *dentry)
+{
+ TRACE();
+ return sf_unlink_aux(parent, dentry, 1);
+}
+
+/**
+ * Rename a regular file / directory.
+ *
+ * @param old_parent inode of the old parent directory
+ * @param old_dentry old directory cache entry
+ * @param new_parent inode of the new parent directory
+ * @param new_dentry new directory cache entry
+ * @param flags flags
+ * @returns 0 on success, Linux error code otherwise
+ */
+static int sf_rename(struct inode *old_parent, struct dentry *old_dentry,
+ struct inode *new_parent, struct dentry *new_dentry
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
+ , unsigned flags
+#endif
+ )
+{
+ int err = 0, rc = VINF_SUCCESS;
+ struct sf_glob_info *sf_g = GET_GLOB_INFO(old_parent->i_sb);
+
+ TRACE();
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
+ if (flags)
+ {
+ LogFunc(("rename with flags=%x\n", flags));
+ return -EINVAL;
+ }
+#endif
+
+ if (sf_g != GET_GLOB_INFO(new_parent->i_sb))
+ {
+ LogFunc(("rename with different roots\n"));
+ err = -EINVAL;
+ }
+ else
+ {
+ struct sf_inode_info *sf_old_i = GET_INODE_INFO(old_parent);
+ struct sf_inode_info *sf_new_i = GET_INODE_INFO(new_parent);
+ /* As we save the relative path inside the inode structure, we need to change
+ this if the rename is successful. */
+ struct sf_inode_info *sf_file_i = GET_INODE_INFO(old_dentry->d_inode);
+ SHFLSTRING *old_path;
+ SHFLSTRING *new_path;
+
+ BUG_ON(!sf_old_i);
+ BUG_ON(!sf_new_i);
+ BUG_ON(!sf_file_i);
+
+ old_path = sf_file_i->path;
+ err = sf_path_from_dentry(__func__, sf_g, sf_new_i,
+ new_dentry, &new_path);
+ if (err)
+ LogFunc(("failed to create new path\n"));
+ else
+ {
+ int fDir = ((old_dentry->d_inode->i_mode & S_IFDIR) != 0);
+
+ rc = VbglR0SfRename(&client_handle, &sf_g->map, old_path,
+ new_path, fDir ? 0 : SHFL_RENAME_FILE | SHFL_RENAME_REPLACE_IF_EXISTS);
+ if (RT_SUCCESS(rc))
+ {
+ kfree(old_path);
+ sf_new_i->force_restat = 1;
+ sf_old_i->force_restat = 1; /* XXX: needed? */
+ /* Set the new relative path in the inode. */
+ sf_file_i->path = new_path;
+ }
+ else
+ {
+ LogFunc(("VbglR0SfRename failed rc=%Rrc\n", rc));
+ err = -RTErrConvertToErrno(rc);
+ kfree(new_path);
+ }
+ }
+ }
+ return err;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+static int sf_symlink(struct inode *parent, struct dentry *dentry, const char *symname)
+{
+ int err;
+ int rc;
+ struct sf_inode_info *sf_i;
+ struct sf_glob_info *sf_g;
+ SHFLSTRING *path, *ssymname;
+ SHFLFSOBJINFO info;
+ int symname_len = strlen(symname) + 1;
+
+ TRACE();
+ sf_g = GET_GLOB_INFO(parent->i_sb);
+ sf_i = GET_INODE_INFO(parent);
+
+ BUG_ON(!sf_g);
+ BUG_ON(!sf_i);
+
+ err = sf_path_from_dentry(__func__, sf_g, sf_i, dentry, &path);
+ if (err)
+ goto fail0;
+
+ ssymname = kmalloc(offsetof(SHFLSTRING, String.utf8) + symname_len, GFP_KERNEL);
+ if (!ssymname)
+ {
+ LogRelFunc(("kmalloc failed, caller=sf_symlink\n"));
+ err = -ENOMEM;
+ goto fail1;
+ }
+
+ ssymname->u16Length = symname_len - 1;
+ ssymname->u16Size = symname_len;
+ memcpy(ssymname->String.utf8, symname, symname_len);
+
+ rc = VbglR0SfSymlink(&client_handle, &sf_g->map, path, ssymname, &info);
+ kfree(ssymname);
+
+ if (RT_FAILURE(rc))
+ {
+ if (rc == VERR_WRITE_PROTECT)
+ {
+ err = -EROFS;
+ goto fail1;
+ }
+ LogFunc(("VbglR0SfSymlink(%s) failed rc=%Rrc\n",
+ sf_i->path->String.utf8, rc));
+ err = -EPROTO;
+ goto fail1;
+ }
+
+ err = sf_instantiate(parent, dentry, path, &info, SHFL_HANDLE_NIL);
+ if (err)
+ {
+ LogFunc(("could not instantiate dentry for %s err=%d\n",
+ sf_i->path->String.utf8, err));
+ goto fail1;
+ }
+
+ sf_i->force_restat = 1;
+ return 0;
+
+fail1:
+ kfree(path);
+fail0:
+ return err;
+}
+#endif
+
+struct inode_operations sf_dir_iops =
+{
+ .lookup = sf_lookup,
+ .create = sf_create,
+ .mkdir = sf_mkdir,
+ .rmdir = sf_rmdir,
+ .unlink = sf_unlink,
+ .rename = sf_rename,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
+ .revalidate = sf_inode_revalidate
+#else
+ .getattr = sf_getattr,
+ .setattr = sf_setattr,
+ .symlink = sf_symlink
+#endif
+};
--- /dev/null
+/* $NetBSD: divdi3.c,v 1.8 2005/12/11 12:24:37 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+/*#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)divdi3.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: divdi3.c,v 1.8 2005/12/11 12:24:37 christos Exp $");
+#endif
+#endif*/ /* LIBC_SCCS and not lint */
+
+#include "quad.h"
+
+/*
+ * Divide two signed quads.
+ * ??? if -1/2 should produce -1 on this machine, this code is wrong
+ */
+quad_t
+__divdi3(a, b)
+ quad_t a, b;
+{
+ u_quad_t ua, ub, uq;
+ int neg = 0;
+
+ ua = a;
+ ub = b;
+
+ if (a < 0)
+ ua = -ua, neg ^= 1;
+ if (b < 0)
+ ub = -ub, neg ^= 1;
+
+ uq = __qdivrem(ua, ub, (u_quad_t *)0);
+ if (neg)
+ uq = - uq;
+ return uq;
+}
--- /dev/null
+../include
\ No newline at end of file
--- /dev/null
+/** @file
+ *
+ * vboxsf -- VirtualBox Guest Additions for Linux:
+ * Operations for symbolic links.
+ */
+
+/*
+ * Copyright (C) 2010-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "vfsmod.h"
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+
+# if LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0)
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
+static const char *sf_follow_link(struct dentry *dentry, void **cookie)
+# else
+static void *sf_follow_link(struct dentry *dentry, struct nameidata *nd)
+# endif
+{
+ struct inode *inode = dentry->d_inode;
+ struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
+ struct sf_inode_info *sf_i = GET_INODE_INFO(inode);
+ int error = -ENOMEM;
+ char *path = (char*)get_zeroed_page(GFP_KERNEL);
+ int rc;
+
+ if (path)
+ {
+ error = 0;
+ rc = VbglR0SfReadLink(&client_handle, &sf_g->map, sf_i->path, PATH_MAX, path);
+ if (RT_FAILURE(rc))
+ {
+ LogFunc(("VbglR0SfReadLink failed, caller=%s, rc=%Rrc\n", __func__, rc));
+ free_page((unsigned long)path);
+ error = -EPROTO;
+ }
+ }
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
+ return error ? ERR_PTR(error) : (*cookie = path);
+# else
+ nd_set_link(nd, error ? ERR_PTR(error) : path);
+ return NULL;
+# endif
+}
+
+# if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0)
+static void sf_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
+{
+ char *page = nd_get_link(nd);
+ if (!IS_ERR(page))
+ free_page((unsigned long)page);
+}
+# endif
+
+# else /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0) */
+static const char *sf_get_link(struct dentry *dentry, struct inode *inode,
+ struct delayed_call *done)
+{
+ struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
+ struct sf_inode_info *sf_i = GET_INODE_INFO(inode);
+ char *path;
+ int rc;
+
+ if (!dentry)
+ return ERR_PTR(-ECHILD);
+ path = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!path)
+ return ERR_PTR(-ENOMEM);
+ rc = VbglR0SfReadLink(&client_handle, &sf_g->map, sf_i->path, PATH_MAX, path);
+ if (RT_FAILURE(rc))
+ {
+ LogFunc(("VbglR0SfReadLink failed, caller=%s, rc=%Rrc\n", __func__, rc));
+ kfree(path);
+ return ERR_PTR(-EPROTO);
+ }
+ set_delayed_call(done, kfree_link, path);
+ return path;
+}
+# endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0) */
+
+struct inode_operations sf_lnk_iops =
+{
+# if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
+ .readlink = generic_readlink,
+# endif
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
+ .get_link = sf_get_link
+# elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
+ .follow_link = sf_follow_link,
+ .put_link = free_page_put_link,
+# else
+ .follow_link = sf_follow_link,
+ .put_link = sf_put_link
+# endif
+};
+
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */
--- /dev/null
+/* $NetBSD: moddi3.c,v 1.8 2005/12/11 12:24:37 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+/*#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)moddi3.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: moddi3.c,v 1.8 2005/12/11 12:24:37 christos Exp $");
+#endif
+#endif*/ /* LIBC_SCCS and not lint */
+
+#include "quad.h"
+
+/*
+ * Return remainder after dividing two signed quads.
+ *
+ * XXX we assume a % b < 0 iff a < 0, but this is actually machine-dependent.
+ */
+quad_t
+__moddi3(a, b)
+ quad_t a, b;
+{
+ u_quad_t ua, ub, ur;
+ int neg = 0;
+
+ ua = a;
+ ub = b;
+
+ if (a < 0)
+ ua = -ua, neg ^= 1;
+ if (b < 0)
+ ub = -ub;
+ (void)__qdivrem(ua, ub, &ur);
+ if (neg)
+ ur = -ur;
+ return (ur);
+}
--- /dev/null
+#ifndef ___product_generated_h___
+#define ___product_generated_h___
+
+#define VBOX_VENDOR "Oracle Corporation"
+#define VBOX_VENDOR_SHORT "Oracle"
+#define VBOX_PRODUCT "Oracle VM VirtualBox"
+#define VBOX_BUILD_PUBLISHER "_Ubuntu"
+#define VBOX_C_YEAR "2017"
+
+#endif
--- /dev/null
+/* $NetBSD: qdivrem.c,v 1.12 2005/12/11 12:24:37 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+/*#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)qdivrem.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: qdivrem.c,v 1.12 2005/12/11 12:24:37 christos Exp $");
+#endif
+#endif*/ /* LIBC_SCCS and not lint */
+
+/*
+ * Multiprecision divide. This algorithm is from Knuth vol. 2 (2nd ed),
+ * section 4.3.1, pp. 257--259.
+ */
+
+#include "quad.h"
+
+#define B ((int)1 << HALF_BITS) /* digit base */
+
+/* Combine two `digits' to make a single two-digit number. */
+#define COMBINE(a, b) (((u_int)(a) << HALF_BITS) | (b))
+
+/* select a type for digits in base B: use unsigned short if they fit */
+#if UINT_MAX == 0xffffffffU && USHRT_MAX >= 0xffff
+typedef unsigned short digit;
+#else
+typedef u_int digit;
+#endif
+
+static void shl __P((digit *p, int len, int sh));
+
+/*
+ * __qdivrem(u, v, rem) returns u/v and, optionally, sets *rem to u%v.
+ *
+ * We do this in base 2-sup-HALF_BITS, so that all intermediate products
+ * fit within u_int. As a consequence, the maximum length dividend and
+ * divisor are 4 `digits' in this base (they are shorter if they have
+ * leading zeros).
+ */
+u_quad_t
+__qdivrem(uq, vq, arq)
+ u_quad_t uq, vq, *arq;
+{
+ union uu tmp;
+ digit *u, *v, *q;
+ digit v1, v2;
+ u_int qhat, rhat, t;
+ int m, n, d, j, i;
+ digit uspace[5], vspace[5], qspace[5];
+
+ /*
+ * Take care of special cases: divide by zero, and u < v.
+ */
+ if (vq == 0) {
+ /* divide by zero. */
+ static volatile const unsigned int zero = 0;
+
+ tmp.ul[H] = tmp.ul[L] = 1 / zero;
+ if (arq)
+ *arq = uq;
+ return (tmp.q);
+ }
+ if (uq < vq) {
+ if (arq)
+ *arq = uq;
+ return (0);
+ }
+ u = &uspace[0];
+ v = &vspace[0];
+ q = &qspace[0];
+
+ /*
+ * Break dividend and divisor into digits in base B, then
+ * count leading zeros to determine m and n. When done, we
+ * will have:
+ * u = (u[1]u[2]...u[m+n]) sub B
+ * v = (v[1]v[2]...v[n]) sub B
+ * v[1] != 0
+ * 1 < n <= 4 (if n = 1, we use a different division algorithm)
+ * m >= 0 (otherwise u < v, which we already checked)
+ * m + n = 4
+ * and thus
+ * m = 4 - n <= 2
+ */
+ tmp.uq = uq;
+ u[0] = 0;
+ u[1] = (digit)HHALF(tmp.ul[H]);
+ u[2] = (digit)LHALF(tmp.ul[H]);
+ u[3] = (digit)HHALF(tmp.ul[L]);
+ u[4] = (digit)LHALF(tmp.ul[L]);
+ tmp.uq = vq;
+ v[1] = (digit)HHALF(tmp.ul[H]);
+ v[2] = (digit)LHALF(tmp.ul[H]);
+ v[3] = (digit)HHALF(tmp.ul[L]);
+ v[4] = (digit)LHALF(tmp.ul[L]);
+ for (n = 4; v[1] == 0; v++) {
+ if (--n == 1) {
+ u_int rbj; /* r*B+u[j] (not root boy jim) */
+ digit q1, q2, q3, q4;
+
+ /*
+ * Change of plan, per exercise 16.
+ * r = 0;
+ * for j = 1..4:
+ * q[j] = floor((r*B + u[j]) / v),
+ * r = (r*B + u[j]) % v;
+ * We unroll this completely here.
+ */
+ t = v[2]; /* nonzero, by definition */
+ q1 = (digit)(u[1] / t);
+ rbj = COMBINE(u[1] % t, u[2]);
+ q2 = (digit)(rbj / t);
+ rbj = COMBINE(rbj % t, u[3]);
+ q3 = (digit)(rbj / t);
+ rbj = COMBINE(rbj % t, u[4]);
+ q4 = (digit)(rbj / t);
+ if (arq)
+ *arq = rbj % t;
+ tmp.ul[H] = COMBINE(q1, q2);
+ tmp.ul[L] = COMBINE(q3, q4);
+ return (tmp.q);
+ }
+ }
+
+ /*
+ * By adjusting q once we determine m, we can guarantee that
+ * there is a complete four-digit quotient at &qspace[1] when
+ * we finally stop.
+ */
+ for (m = 4 - n; u[1] == 0; u++)
+ m--;
+ for (i = 4 - m; --i >= 0;)
+ q[i] = 0;
+ q += 4 - m;
+
+ /*
+ * Here we run Program D, translated from MIX to C and acquiring
+ * a few minor changes.
+ *
+ * D1: choose multiplier 1 << d to ensure v[1] >= B/2.
+ */
+ d = 0;
+ for (t = v[1]; t < B / 2; t <<= 1)
+ d++;
+ if (d > 0) {
+ shl(&u[0], m + n, d); /* u <<= d */
+ shl(&v[1], n - 1, d); /* v <<= d */
+ }
+ /*
+ * D2: j = 0.
+ */
+ j = 0;
+ v1 = v[1]; /* for D3 -- note that v[1..n] are constant */
+ v2 = v[2]; /* for D3 */
+ do {
+ digit uj0, uj1, uj2;
+
+ /*
+ * D3: Calculate qhat (\^q, in TeX notation).
+ * Let qhat = min((u[j]*B + u[j+1])/v[1], B-1), and
+ * let rhat = (u[j]*B + u[j+1]) mod v[1].
+ * While rhat < B and v[2]*qhat > rhat*B+u[j+2],
+ * decrement qhat and increase rhat correspondingly.
+ * Note that if rhat >= B, v[2]*qhat < rhat*B.
+ */
+ uj0 = u[j + 0]; /* for D3 only -- note that u[j+...] change */
+ uj1 = u[j + 1]; /* for D3 only */
+ uj2 = u[j + 2]; /* for D3 only */
+ if (uj0 == v1) {
+ qhat = B;
+ rhat = uj1;
+ goto qhat_too_big;
+ } else {
+ u_int nn = COMBINE(uj0, uj1);
+ qhat = nn / v1;
+ rhat = nn % v1;
+ }
+ while (v2 * qhat > COMBINE(rhat, uj2)) {
+ qhat_too_big:
+ qhat--;
+ if ((rhat += v1) >= B)
+ break;
+ }
+ /*
+ * D4: Multiply and subtract.
+ * The variable `t' holds any borrows across the loop.
+ * We split this up so that we do not require v[0] = 0,
+ * and to eliminate a final special case.
+ */
+ for (t = 0, i = n; i > 0; i--) {
+ t = u[i + j] - v[i] * qhat - t;
+ u[i + j] = (digit)LHALF(t);
+ t = (B - HHALF(t)) & (B - 1);
+ }
+ t = u[j] - t;
+ u[j] = (digit)LHALF(t);
+ /*
+ * D5: test remainder.
+ * There is a borrow if and only if HHALF(t) is nonzero;
+ * in that (rare) case, qhat was too large (by exactly 1).
+ * Fix it by adding v[1..n] to u[j..j+n].
+ */
+ if (HHALF(t)) {
+ qhat--;
+ for (t = 0, i = n; i > 0; i--) { /* D6: add back. */
+ t += u[i + j] + v[i];
+ u[i + j] = (digit)LHALF(t);
+ t = HHALF(t);
+ }
+ u[j] = (digit)LHALF(u[j] + t);
+ }
+ q[j] = (digit)qhat;
+ } while (++j <= m); /* D7: loop on j. */
+
+ /*
+ * If caller wants the remainder, we have to calculate it as
+ * u[m..m+n] >> d (this is at most n digits and thus fits in
+ * u[m+1..m+n], but we may need more source digits).
+ */
+ if (arq) {
+ if (d) {
+ for (i = m + n; i > m; --i)
+ u[i] = (digit)(((u_int)u[i] >> d) |
+ LHALF((u_int)u[i - 1] << (HALF_BITS - d)));
+ u[i] = 0;
+ }
+ tmp.ul[H] = COMBINE(uspace[1], uspace[2]);
+ tmp.ul[L] = COMBINE(uspace[3], uspace[4]);
+ *arq = tmp.q;
+ }
+
+ tmp.ul[H] = COMBINE(qspace[1], qspace[2]);
+ tmp.ul[L] = COMBINE(qspace[3], qspace[4]);
+ return (tmp.q);
+}
+
+/*
+ * Shift p[0]..p[len] left `sh' bits, ignoring any bits that
+ * `fall out' the left (there never will be any such anyway).
+ * We may assume len >= 0. NOTE THAT THIS WRITES len+1 DIGITS.
+ */
+static void
+shl(digit *p, int len, int sh)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ p[i] = (digit)(LHALF((u_int)p[i] << sh) |
+ ((u_int)p[i + 1] >> (HALF_BITS - sh)));
+ p[i] = (digit)(LHALF((u_int)p[i] << sh));
+}
--- /dev/null
+/* $NetBSD: quad.h,v 1.17 2005/12/11 12:24:37 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ * @(#)quad.h 8.1 (Berkeley) 6/4/93
+ */
+
+/*
+ * Quad arithmetic.
+ *
+ * This library makes the following assumptions:
+ *
+ * - The type long long (aka quad_t) exists.
+ *
+ * - A quad variable is exactly twice as long as `int'.
+ *
+ * - The machine's arithmetic is two's complement.
+ *
+ * This library can provide 128-bit arithmetic on a machine with 128-bit
+ * quads and 64-bit ints, for instance, or 96-bit arithmetic on machines
+ * with 48-bit ints.
+ */
+
+#if 0 /* iprt */
+#include <sys/types.h>
+#if !defined(_KERNEL) && !defined(_STANDALONE)
+#include <limits.h>
+#else
+#include <machine/limits.h>
+#endif
+#else /* iprt */
+# include <iprt/types.h>
+# include <iprt/nocrt/limits.h>
+# undef __P
+# define __P(a) a
+# undef __GNUC_PREREQ__
+# define __GNUC_PREREQ__(m1,m2) 1
+# if 1 /* ASSUMES: little endian */
+# define _QUAD_HIGHWORD 1
+# define _QUAD_LOWWORD 0
+# else
+# define _QUAD_HIGHWORD 0
+# define _QUAD_LOWWORD 1
+# endif
+# if !defined(RT_OS_LINUX) || !defined(__KERNEL__) /* (linux/types.h defines u_int) */
+ typedef unsigned int u_int;
+# endif
+# if !defined(RT_OS_SOLARIS)
+ typedef int64_t quad_t;
+# else
+# define quad_t int64_t
+# endif
+ typedef uint64_t u_quad_t;
+ typedef quad_t *qaddr_t;
+#endif /* iprt */
+
+/*
+ * Depending on the desired operation, we view a `long long' (aka quad_t) in
+ * one or more of the following formats.
+ */
+union uu {
+ quad_t q; /* as a (signed) quad */
+ u_quad_t uq; /* as an unsigned quad */
+ int sl[2]; /* as two signed ints */
+ u_int ul[2]; /* as two unsigned ints */
+};
+
+/*
+ * Define high and low parts of a quad_t.
+ */
+#define H _QUAD_HIGHWORD
+#define L _QUAD_LOWWORD
+
+/*
+ * Total number of bits in a quad_t and in the pieces that make it up.
+ * These are used for shifting, and also below for halfword extraction
+ * and assembly.
+ */
+#define QUAD_BITS (sizeof(quad_t) * CHAR_BIT)
+#define INT_BITS (sizeof(int) * CHAR_BIT)
+#define HALF_BITS (sizeof(int) * CHAR_BIT / 2)
+
+/*
+ * Extract high and low shortwords from longword, and move low shortword of
+ * longword to upper half of long, i.e., produce the upper longword of
+ * ((quad_t)(x) << (number_of_bits_in_int/2)). (`x' must actually be u_int.)
+ *
+ * These are used in the multiply code, to split a longword into upper
+ * and lower halves, and to reassemble a product as a quad_t, shifted left
+ * (sizeof(int)*CHAR_BIT/2).
+ */
+#define HHALF(x) ((u_int)(x) >> HALF_BITS)
+#define LHALF(x) ((u_int)(x) & (((int)1 << HALF_BITS) - 1))
+#define LHUP(x) ((u_int)(x) << HALF_BITS)
+
+/*
+ * XXX
+ * Compensate for gcc 1 vs gcc 2. Gcc 1 defines ?sh?di3's second argument
+ * as u_quad_t, while gcc 2 correctly uses int. Unfortunately, we still use
+ * both compilers.
+ */
+#if __GNUC_PREREQ__(2, 0) || defined(lint)
+typedef unsigned int qshift_t;
+#else
+typedef u_quad_t qshift_t;
+#endif
+
+RT_C_DECLS_BEGIN
+quad_t __adddi3 __P((quad_t, quad_t));
+quad_t __anddi3 __P((quad_t, quad_t));
+quad_t __ashldi3 __P((quad_t, qshift_t));
+quad_t __ashrdi3 __P((quad_t, qshift_t));
+int __cmpdi2 __P((quad_t, quad_t ));
+quad_t __divdi3 __P((quad_t, quad_t));
+quad_t __fixdfdi __P((double));
+quad_t __fixsfdi __P((float));
+u_quad_t __fixunsdfdi __P((double));
+u_quad_t __fixunssfdi __P((float));
+double __floatdidf __P((quad_t));
+float __floatdisf __P((quad_t));
+double __floatunsdidf __P((u_quad_t));
+quad_t __iordi3 __P((quad_t, quad_t));
+quad_t __lshldi3 __P((quad_t, qshift_t));
+quad_t __lshrdi3 __P((quad_t, qshift_t));
+quad_t __moddi3 __P((quad_t, quad_t));
+quad_t __muldi3 __P((quad_t, quad_t));
+quad_t __negdi2 __P((quad_t));
+quad_t __one_cmpldi2 __P((quad_t));
+u_quad_t __qdivrem __P((u_quad_t, u_quad_t, u_quad_t *));
+quad_t __subdi3 __P((quad_t, quad_t));
+int __ucmpdi2 __P((u_quad_t, u_quad_t));
+u_quad_t __udivdi3 __P((u_quad_t, u_quad_t ));
+u_quad_t __umoddi3 __P((u_quad_t, u_quad_t ));
+quad_t __xordi3 __P((quad_t, quad_t));
+RT_C_DECLS_END
--- /dev/null
+../r0drv
\ No newline at end of file
--- /dev/null
+/* $Id: regops.c $ */
+/** @file
+ * vboxsf - VBox Linux Shared Folders, Regular file inode and file operations.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*
+ * Limitations: only COW memory mapping is supported
+ */
+
+#include "vfsmod.h"
+
+static void *alloc_bounce_buffer(size_t *tmp_sizep, PRTCCPHYS physp, size_t
+ xfer_size, const char *caller)
+{
+ size_t tmp_size;
+ void *tmp;
+
+ /* try for big first. */
+ tmp_size = RT_ALIGN_Z(xfer_size, PAGE_SIZE);
+ if (tmp_size > 16U*_1K)
+ tmp_size = 16U*_1K;
+ tmp = kmalloc(tmp_size, GFP_KERNEL);
+ if (!tmp)
+ {
+ /* fall back on a page sized buffer. */
+ tmp = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!tmp)
+ {
+ LogRel(("%s: could not allocate bounce buffer for xfer_size=%zu %s\n", caller, xfer_size));
+ return NULL;
+ }
+ tmp_size = PAGE_SIZE;
+ }
+
+ *tmp_sizep = tmp_size;
+ *physp = virt_to_phys(tmp);
+ return tmp;
+}
+
+static void free_bounce_buffer(void *tmp)
+{
+ kfree (tmp);
+}
+
+
+/* fops */
+static int sf_reg_read_aux(const char *caller, struct sf_glob_info *sf_g,
+ struct sf_reg_info *sf_r, void *buf,
+ uint32_t *nread, uint64_t pos)
+{
+ /** @todo bird: yes, kmap() and kmalloc() input only. Since the buffer is
+ * contiguous in physical memory (kmalloc or single page), we should
+ * use a physical address here to speed things up. */
+ int rc = VbglR0SfRead(&client_handle, &sf_g->map, sf_r->handle,
+ pos, nread, buf, false /* already locked? */);
+ if (RT_FAILURE(rc))
+ {
+ LogFunc(("VbglR0SfRead failed. caller=%s, rc=%Rrc\n", caller, rc));
+ return -EPROTO;
+ }
+ return 0;
+}
+
+static int sf_reg_write_aux(const char *caller, struct sf_glob_info *sf_g,
+ struct sf_reg_info *sf_r, void *buf,
+ uint32_t *nwritten, uint64_t pos)
+{
+ /** @todo bird: yes, kmap() and kmalloc() input only. Since the buffer is
+ * contiguous in physical memory (kmalloc or single page), we should
+ * use a physical address here to speed things up. */
+ int rc = VbglR0SfWrite(&client_handle, &sf_g->map, sf_r->handle,
+ pos, nwritten, buf, false /* already locked? */);
+ if (RT_FAILURE(rc))
+ {
+ LogFunc(("VbglR0SfWrite failed. caller=%s, rc=%Rrc\n",
+ caller, rc));
+ return -EPROTO;
+ }
+ return 0;
+}
+
+/**
+ * Read from a regular file.
+ *
+ * @param file the file
+ * @param buf the buffer
+ * @param size length of the buffer
+ * @param off offset within the file
+ * @returns the number of read bytes on success, Linux error code otherwise
+ */
+static ssize_t sf_reg_read(struct file *file, char *buf, size_t size, loff_t *off)
+{
+ int err;
+ void *tmp;
+ RTCCPHYS tmp_phys;
+ size_t tmp_size;
+ size_t left = size;
+ ssize_t total_bytes_read = 0;
+ struct inode *inode = GET_F_DENTRY(file)->d_inode;
+ struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
+ struct sf_reg_info *sf_r = file->private_data;
+ loff_t pos = *off;
+
+ TRACE();
+ if (!S_ISREG(inode->i_mode))
+ {
+ LogFunc(("read from non regular file %d\n", inode->i_mode));
+ return -EINVAL;
+ }
+
+ /** XXX Check read permission according to inode->i_mode! */
+
+ if (!size)
+ return 0;
+
+ tmp = alloc_bounce_buffer(&tmp_size, &tmp_phys, size, __PRETTY_FUNCTION__);
+ if (!tmp)
+ return -ENOMEM;
+
+ while (left)
+ {
+ uint32_t to_read, nread;
+
+ to_read = tmp_size;
+ if (to_read > left)
+ to_read = (uint32_t) left;
+
+ nread = to_read;
+
+ err = sf_reg_read_aux(__func__, sf_g, sf_r, tmp, &nread, pos);
+ if (err)
+ goto fail;
+
+ if (copy_to_user(buf, tmp, nread))
+ {
+ err = -EFAULT;
+ goto fail;
+ }
+
+ pos += nread;
+ left -= nread;
+ buf += nread;
+ total_bytes_read += nread;
+ if (nread != to_read)
+ break;
+ }
+
+ *off += total_bytes_read;
+ free_bounce_buffer(tmp);
+ return total_bytes_read;
+
+fail:
+ free_bounce_buffer(tmp);
+ return err;
+}
+
+/**
+ * Write to a regular file.
+ *
+ * @param file the file
+ * @param buf the buffer
+ * @param size length of the buffer
+ * @param off offset within the file
+ * @returns the number of written bytes on success, Linux error code otherwise
+ */
+static ssize_t sf_reg_write(struct file *file, const char *buf, size_t size, loff_t *off)
+{
+ int err;
+ void *tmp;
+ RTCCPHYS tmp_phys;
+ size_t tmp_size;
+ size_t left = size;
+ ssize_t total_bytes_written = 0;
+ struct inode *inode = GET_F_DENTRY(file)->d_inode;
+ struct sf_inode_info *sf_i = GET_INODE_INFO(inode);
+ struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
+ struct sf_reg_info *sf_r = file->private_data;
+ loff_t pos;
+
+ TRACE();
+ BUG_ON(!sf_i);
+ BUG_ON(!sf_g);
+ BUG_ON(!sf_r);
+
+ if (!S_ISREG(inode->i_mode))
+ {
+ LogFunc(("write to non regular file %d\n", inode->i_mode));
+ return -EINVAL;
+ }
+
+ pos = *off;
+ if (file->f_flags & O_APPEND)
+ {
+ pos = inode->i_size;
+ *off = pos;
+ }
+
+ /** XXX Check write permission according to inode->i_mode! */
+
+ if (!size)
+ return 0;
+
+ tmp = alloc_bounce_buffer(&tmp_size, &tmp_phys, size, __PRETTY_FUNCTION__);
+ if (!tmp)
+ return -ENOMEM;
+
+ while (left)
+ {
+ uint32_t to_write, nwritten;
+
+ to_write = tmp_size;
+ if (to_write > left)
+ to_write = (uint32_t) left;
+
+ nwritten = to_write;
+
+ if (copy_from_user(tmp, buf, to_write))
+ {
+ err = -EFAULT;
+ goto fail;
+ }
+
+#if 1
+ if (VbglR0CanUsePhysPageList())
+ {
+ err = VbglR0SfWritePhysCont(&client_handle, &sf_g->map, sf_r->handle,
+ pos, &nwritten, tmp_phys);
+ err = RT_FAILURE(err) ? -EPROTO : 0;
+ }
+ else
+#endif
+ err = sf_reg_write_aux(__func__, sf_g, sf_r, tmp, &nwritten, pos);
+ if (err)
+ goto fail;
+
+ pos += nwritten;
+ left -= nwritten;
+ buf += nwritten;
+ total_bytes_written += nwritten;
+ if (nwritten != to_write)
+ break;
+ }
+
+ *off += total_bytes_written;
+ if (*off > inode->i_size)
+ inode->i_size = *off;
+
+ sf_i->force_restat = 1;
+ free_bounce_buffer(tmp);
+ return total_bytes_written;
+
+fail:
+ free_bounce_buffer(tmp);
+ return err;
+}
+
+/**
+ * Open a regular file.
+ *
+ * @param inode the inode
+ * @param file the file
+ * @returns 0 on success, Linux error code otherwise
+ */
+static int sf_reg_open(struct inode *inode, struct file *file)
+{
+ int rc, rc_linux = 0;
+ struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
+ struct sf_inode_info *sf_i = GET_INODE_INFO(inode);
+ struct sf_reg_info *sf_r;
+ SHFLCREATEPARMS params;
+
+ TRACE();
+ BUG_ON(!sf_g);
+ BUG_ON(!sf_i);
+
+ LogFunc(("open %s\n", sf_i->path->String.utf8));
+
+ sf_r = kmalloc(sizeof(*sf_r), GFP_KERNEL);
+ if (!sf_r)
+ {
+ LogRelFunc(("could not allocate reg info\n"));
+ return -ENOMEM;
+ }
+
+ /* Already open? */
+ if (sf_i->handle != SHFL_HANDLE_NIL)
+ {
+ /*
+ * This inode was created with sf_create_aux(). Check the CreateFlags:
+ * O_CREAT, O_TRUNC: inherent true (file was just created). Not sure
+ * about the access flags (SHFL_CF_ACCESS_*).
+ */
+ sf_i->force_restat = 1;
+ sf_r->handle = sf_i->handle;
+ sf_i->handle = SHFL_HANDLE_NIL;
+ sf_i->file = file;
+ file->private_data = sf_r;
+ return 0;
+ }
+
+ RT_ZERO(params);
+ params.Handle = SHFL_HANDLE_NIL;
+ /* We check the value of params.Handle afterwards to find out if
+ * the call succeeded or failed, as the API does not seem to cleanly
+ * distinguish error and informational messages.
+ *
+ * Furthermore, we must set params.Handle to SHFL_HANDLE_NIL to
+ * make the shared folders host service use our fMode parameter */
+
+ if (file->f_flags & O_CREAT)
+ {
+ LogFunc(("O_CREAT set\n"));
+ params.CreateFlags |= SHFL_CF_ACT_CREATE_IF_NEW;
+ /* We ignore O_EXCL, as the Linux kernel seems to call create
+ beforehand itself, so O_EXCL should always fail. */
+ if (file->f_flags & O_TRUNC)
+ {
+ LogFunc(("O_TRUNC set\n"));
+ params.CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS;
+ }
+ else
+ params.CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS;
+ }
+ else
+ {
+ params.CreateFlags |= SHFL_CF_ACT_FAIL_IF_NEW;
+ if (file->f_flags & O_TRUNC)
+ {
+ LogFunc(("O_TRUNC set\n"));
+ params.CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS;
+ }
+ }
+
+ switch (file->f_flags & O_ACCMODE)
+ {
+ case O_RDONLY:
+ params.CreateFlags |= SHFL_CF_ACCESS_READ;
+ break;
+
+ case O_WRONLY:
+ params.CreateFlags |= SHFL_CF_ACCESS_WRITE;
+ break;
+
+ case O_RDWR:
+ params.CreateFlags |= SHFL_CF_ACCESS_READWRITE;
+ break;
+
+ default:
+ BUG ();
+ }
+
+ if (file->f_flags & O_APPEND)
+ {
+ LogFunc(("O_APPEND set\n"));
+ params.CreateFlags |= SHFL_CF_ACCESS_APPEND;
+ }
+
+ params.Info.Attr.fMode = inode->i_mode;
+ LogFunc(("sf_reg_open: calling VbglR0SfCreate, file %s, flags=%#x, %#x\n",
+ sf_i->path->String.utf8 , file->f_flags, params.CreateFlags));
+ rc = VbglR0SfCreate(&client_handle, &sf_g->map, sf_i->path, ¶ms);
+ if (RT_FAILURE(rc))
+ {
+ LogFunc(("VbglR0SfCreate failed flags=%d,%#x rc=%Rrc\n",
+ file->f_flags, params.CreateFlags, rc));
+ kfree(sf_r);
+ return -RTErrConvertToErrno(rc);
+ }
+
+ if (SHFL_HANDLE_NIL == params.Handle)
+ {
+ switch (params.Result)
+ {
+ case SHFL_PATH_NOT_FOUND:
+ case SHFL_FILE_NOT_FOUND:
+ rc_linux = -ENOENT;
+ break;
+ case SHFL_FILE_EXISTS:
+ rc_linux = -EEXIST;
+ break;
+ default:
+ break;
+ }
+ }
+
+ sf_i->force_restat = 1;
+ sf_r->handle = params.Handle;
+ sf_i->file = file;
+ file->private_data = sf_r;
+ return rc_linux;
+}
+
+/**
+ * Close a regular file.
+ *
+ * @param inode the inode
+ * @param file the file
+ * @returns 0 on success, Linux error code otherwise
+ */
+static int sf_reg_release(struct inode *inode, struct file *file)
+{
+ int rc;
+ struct sf_reg_info *sf_r;
+ struct sf_glob_info *sf_g;
+ struct sf_inode_info *sf_i = GET_INODE_INFO(inode);
+
+ TRACE();
+ sf_g = GET_GLOB_INFO(inode->i_sb);
+ sf_r = file->private_data;
+
+ BUG_ON(!sf_g);
+ BUG_ON(!sf_r);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
+ /* See the smbfs source (file.c). mmap in particular can cause data to be
+ * written to the file after it is closed, which we can't cope with. We
+ * copy and paste the body of filemap_write_and_wait() here as it was not
+ * defined before 2.6.6 and not exported until quite a bit later. */
+ /* filemap_write_and_wait(inode->i_mapping); */
+ if ( inode->i_mapping->nrpages
+ && filemap_fdatawrite(inode->i_mapping) != -EIO)
+ filemap_fdatawait(inode->i_mapping);
+#endif
+ rc = VbglR0SfClose(&client_handle, &sf_g->map, sf_r->handle);
+ if (RT_FAILURE(rc))
+ LogFunc(("VbglR0SfClose failed rc=%Rrc\n", rc));
+
+ kfree(sf_r);
+ sf_i->file = NULL;
+ sf_i->handle = SHFL_HANDLE_NIL;
+ file->private_data = NULL;
+ return 0;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+static int sf_reg_fault(struct vm_fault *vmf)
+#elif LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 25)
+static int sf_reg_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+static struct page *sf_reg_nopage(struct vm_area_struct *vma, unsigned long vaddr, int *type)
+# define SET_TYPE(t) *type = (t)
+#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) */
+static struct page *sf_reg_nopage(struct vm_area_struct *vma, unsigned long vaddr, int unused)
+# define SET_TYPE(t)
+#endif
+{
+ struct page *page;
+ char *buf;
+ loff_t off;
+ uint32_t nread = PAGE_SIZE;
+ int err;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+ struct vm_area_struct *vma = vmf->vma;
+#endif
+ struct file *file = vma->vm_file;
+ struct inode *inode = GET_F_DENTRY(file)->d_inode;
+ struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
+ struct sf_reg_info *sf_r = file->private_data;
+
+ TRACE();
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 25)
+ if (vmf->pgoff > vma->vm_end)
+ return VM_FAULT_SIGBUS;
+#else
+ if (vaddr > vma->vm_end)
+ {
+ SET_TYPE(VM_FAULT_SIGBUS);
+ return NOPAGE_SIGBUS;
+ }
+#endif
+
+ /* Don't use GFP_HIGHUSER as long as sf_reg_read_aux() calls VbglR0SfRead()
+ * which works on virtual addresses. On Linux cannot reliably determine the
+ * physical address for high memory, see rtR0MemObjNativeLockKernel(). */
+ page = alloc_page(GFP_USER);
+ if (!page) {
+ LogRelFunc(("failed to allocate page\n"));
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 25)
+ return VM_FAULT_OOM;
+#else
+ SET_TYPE(VM_FAULT_OOM);
+ return NOPAGE_OOM;
+#endif
+ }
+
+ buf = kmap(page);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 25)
+ off = (vmf->pgoff << PAGE_SHIFT);
+#else
+ off = (vaddr - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
+#endif
+ err = sf_reg_read_aux(__func__, sf_g, sf_r, buf, &nread, off);
+ if (err)
+ {
+ kunmap(page);
+ put_page(page);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 25)
+ return VM_FAULT_SIGBUS;
+#else
+ SET_TYPE(VM_FAULT_SIGBUS);
+ return NOPAGE_SIGBUS;
+#endif
+ }
+
+ BUG_ON (nread > PAGE_SIZE);
+ if (!nread)
+ {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 25)
+ clear_user_page(page_address(page), vmf->pgoff, page);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+ clear_user_page(page_address(page), vaddr, page);
+#else
+ clear_user_page(page_address(page), vaddr);
+#endif
+ }
+ else
+ memset(buf + nread, 0, PAGE_SIZE - nread);
+
+ flush_dcache_page(page);
+ kunmap(page);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 25)
+ vmf->page = page;
+ return 0;
+#else
+ SET_TYPE(VM_FAULT_MAJOR);
+ return page;
+#endif
+}
+
+static struct vm_operations_struct sf_vma_ops =
+{
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 25)
+ .fault = sf_reg_fault
+#else
+ .nopage = sf_reg_nopage
+#endif
+};
+
+static int sf_reg_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ TRACE();
+ if (vma->vm_flags & VM_SHARED)
+ {
+ LogFunc(("shared mmapping not available\n"));
+ return -EINVAL;
+ }
+
+ vma->vm_ops = &sf_vma_ops;
+ return 0;
+}
+
+struct file_operations sf_reg_fops =
+{
+ .read = sf_reg_read,
+ .open = sf_reg_open,
+ .write = sf_reg_write,
+ .release = sf_reg_release,
+ .mmap = sf_reg_mmap,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
+ .splice_read = generic_file_splice_read,
+# else
+ .sendfile = generic_file_sendfile,
+# endif
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
+ .read_iter = generic_file_read_iter,
+ .write_iter = generic_file_write_iter,
+# else
+ .aio_read = generic_file_aio_read,
+ .aio_write = generic_file_aio_write,
+# endif
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
+ .fsync = noop_fsync,
+# else
+ .fsync = simple_sync_file,
+# endif
+ .llseek = generic_file_llseek,
+#endif
+};
+
+
+struct inode_operations sf_reg_iops =
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
+ .revalidate = sf_inode_revalidate
+#else
+ .getattr = sf_getattr,
+ .setattr = sf_setattr
+#endif
+};
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+static int sf_readpage(struct file *file, struct page *page)
+{
+ struct inode *inode = GET_F_DENTRY(file)->d_inode;
+ struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
+ struct sf_reg_info *sf_r = file->private_data;
+ uint32_t nread = PAGE_SIZE;
+ char *buf;
+ loff_t off = ((loff_t)page->index) << PAGE_SHIFT;
+ int ret;
+
+ TRACE();
+
+ buf = kmap(page);
+ ret = sf_reg_read_aux(__func__, sf_g, sf_r, buf, &nread, off);
+ if (ret)
+ {
+ kunmap(page);
+ if (PageLocked(page))
+ unlock_page(page);
+ return ret;
+ }
+ BUG_ON(nread > PAGE_SIZE);
+ memset(&buf[nread], 0, PAGE_SIZE - nread);
+ flush_dcache_page(page);
+ kunmap(page);
+ SetPageUptodate(page);
+ unlock_page(page);
+ return 0;
+}
+
+static int
+sf_writepage(struct page *page, struct writeback_control *wbc)
+{
+ struct address_space *mapping = page->mapping;
+ struct inode *inode = mapping->host;
+ struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
+ struct sf_inode_info *sf_i = GET_INODE_INFO(inode);
+ struct file *file = sf_i->file;
+ struct sf_reg_info *sf_r = file->private_data;
+ char *buf;
+ uint32_t nwritten = PAGE_SIZE;
+ int end_index = inode->i_size >> PAGE_SHIFT;
+ loff_t off = ((loff_t) page->index) << PAGE_SHIFT;
+ int err;
+
+ TRACE();
+
+ if (page->index >= end_index)
+ nwritten = inode->i_size & (PAGE_SIZE-1);
+
+ buf = kmap(page);
+
+ err = sf_reg_write_aux(__func__, sf_g, sf_r, buf, &nwritten, off);
+ if (err < 0)
+ {
+ ClearPageUptodate(page);
+ goto out;
+ }
+
+ if (off > inode->i_size)
+ inode->i_size = off;
+
+ if (PageError(page))
+ ClearPageError(page);
+ err = 0;
+
+out:
+ kunmap(page);
+
+ unlock_page(page);
+ return err;
+}
+
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
+int sf_write_begin(struct file *file, struct address_space *mapping, loff_t pos,
+ unsigned len, unsigned flags, struct page **pagep, void **fsdata)
+{
+ TRACE();
+
+ return simple_write_begin(file, mapping, pos, len, flags, pagep, fsdata);
+}
+
+int sf_write_end(struct file *file, struct address_space *mapping, loff_t pos,
+ unsigned len, unsigned copied, struct page *page, void *fsdata)
+{
+ struct inode *inode = mapping->host;
+ struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
+ struct sf_reg_info *sf_r = file->private_data;
+ void *buf;
+ unsigned from = pos & (PAGE_SIZE - 1);
+ uint32_t nwritten = len;
+ int err;
+
+ TRACE();
+
+ buf = kmap(page);
+ err = sf_reg_write_aux(__func__, sf_g, sf_r, buf+from, &nwritten, pos);
+ kunmap(page);
+
+ if (!PageUptodate(page) && err == PAGE_SIZE)
+ SetPageUptodate(page);
+
+ if (err >= 0) {
+ pos += nwritten;
+ if (pos > inode->i_size)
+ inode->i_size = pos;
+ }
+
+ unlock_page(page);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0)
+ put_page(page);
+#else
+ page_cache_release(page);
+#endif
+
+ return nwritten;
+}
+
+# endif /* KERNEL_VERSION >= 2.6.24 */
+
+struct address_space_operations sf_reg_aops =
+{
+ .readpage = sf_readpage,
+ .writepage = sf_writepage,
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
+ .write_begin = sf_write_begin,
+ .write_end = sf_write_end,
+# else
+ .prepare_write = simple_prepare_write,
+ .commit_write = simple_commit_write,
+# endif
+};
+#endif
--- /dev/null
+#define VBOX_SVN_REV 117968
--- /dev/null
+/* $NetBSD: udivdi3.c,v 1.8 2005/12/11 12:24:37 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+/*#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)udivdi3.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: udivdi3.c,v 1.8 2005/12/11 12:24:37 christos Exp $");
+#endif
+#endif*/ /* LIBC_SCCS and not lint */
+
+#include "quad.h"
+
+/*
+ * Divide two unsigned quads.
+ */
+u_quad_t
+__udivdi3(a, b)
+ u_quad_t a, b;
+{
+
+ return (__qdivrem(a, b, (u_quad_t *)0));
+}
--- /dev/null
+/* $Id: udivmoddi4.c $ */
+/** @file
+ * IPRT - __udivmoddi4 implementation
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#include <iprt/stdint.h>
+#include <iprt/uint64.h>
+
+uint64_t __udivmoddi4(uint64_t u64A, uint64_t u64B, uint64_t *pu64R);
+
+/**
+ * __udivmoddi4() implementation to satisfy external references from 32-bit
+ * code generated by gcc-7 or later.
+ *
+ * @param u64A The divident value.
+ * @param u64B The divisor value.
+ * @param pu64R A pointer to the reminder. May be NULL.
+ * @returns u64A / u64B
+ */
+uint64_t __udivmoddi4(uint64_t u64A, uint64_t u64B, uint64_t *pu64R)
+{
+ RTUINT64U Divident;
+ RTUINT64U Divisor;
+ RTUINT64U Quotient;
+ RTUINT64U Reminder;
+ Divident.u = u64A;
+ Divisor.u = u64B;
+ RTUInt64DivRem(&Quotient, &Reminder, &Divident, &Divisor);
+ if (pu64R)
+ *pu64R = Reminder.u;
+ return Quotient.u;
+}
--- /dev/null
+/* $NetBSD: umoddi3.c,v 1.8 2005/12/11 12:24:37 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+/*#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)umoddi3.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: umoddi3.c,v 1.8 2005/12/11 12:24:37 christos Exp $");
+#endif
+#endif*/ /* LIBC_SCCS and not lint */
+
+#include "quad.h"
+
+/*
+ * Return remainder after dividing two unsigned quads.
+ */
+u_quad_t
+__umoddi3(a, b)
+ u_quad_t a, b;
+{
+ u_quad_t r;
+
+ (void)__qdivrem(a, b, &r);
+ return (r);
+}
--- /dev/null
+/** @file
+ *
+ * vboxsf -- VirtualBox Guest Additions for Linux:
+ * Utility functions.
+ * Mainly conversion from/to VirtualBox/Linux data structures
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "vfsmod.h"
+#include <iprt/asm.h>
+#include <linux/nfs_fs.h>
+#include <linux/vfs.h>
+
+/* #define USE_VMALLOC */
+
+/*
+ * sf_reg_aops and sf_backing_dev_info are just quick implementations to make
+ * sendfile work. For more information have a look at
+ *
+ * http://us1.samba.org/samba/ftp/cifs-cvs/ols2006-fs-tutorial-smf.odp
+ *
+ * and the sample implementation
+ *
+ * http://pserver.samba.org/samba/ftp/cifs-cvs/samplefs.tar.gz
+ */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
+static void sf_ftime_from_timespec(time_t *time, RTTIMESPEC *ts)
+{
+ int64_t t = RTTimeSpecGetNano(ts);
+
+ do_div(t, 1000000000);
+ *time = t;
+}
+
+static void sf_timespec_from_ftime(RTTIMESPEC *ts, time_t *time)
+{
+ int64_t t = 1000000000 * *time;
+ RTTimeSpecSetNano(ts, t);
+}
+#else /* >= 2.6.0 */
+static void sf_ftime_from_timespec(struct timespec *tv, RTTIMESPEC *ts)
+{
+ int64_t t = RTTimeSpecGetNano(ts);
+ int64_t nsec;
+
+ nsec = do_div(t, 1000000000);
+ tv->tv_sec = t;
+ tv->tv_nsec = nsec;
+}
+
+static void sf_timespec_from_ftime(RTTIMESPEC *ts, struct timespec *tv)
+{
+ int64_t t = (int64_t)tv->tv_nsec + (int64_t)tv->tv_sec * 1000000000;
+ RTTimeSpecSetNano(ts, t);
+}
+#endif /* >= 2.6.0 */
+
+/* set [inode] attributes based on [info], uid/gid based on [sf_g] */
+void sf_init_inode(struct sf_glob_info *sf_g, struct inode *inode,
+ PSHFLFSOBJINFO info)
+{
+ PSHFLFSOBJATTR attr;
+ int mode;
+
+ TRACE();
+
+ attr = &info->Attr;
+
+#define mode_set(r) attr->fMode & (RTFS_UNIX_##r) ? (S_##r) : 0;
+ mode = mode_set(ISUID);
+ mode |= mode_set(ISGID);
+
+ mode |= mode_set(IRUSR);
+ mode |= mode_set(IWUSR);
+ mode |= mode_set(IXUSR);
+
+ mode |= mode_set(IRGRP);
+ mode |= mode_set(IWGRP);
+ mode |= mode_set(IXGRP);
+
+ mode |= mode_set(IROTH);
+ mode |= mode_set(IWOTH);
+ mode |= mode_set(IXOTH);
+
+#undef mode_set
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+ inode->i_mapping->a_ops = &sf_reg_aops;
+# if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 19, 0)
+ /* XXX Was this ever necessary? */
+ inode->i_mapping->backing_dev_info = &sf_g->bdi;
+# endif
+#endif
+
+ if (RTFS_IS_DIRECTORY(attr->fMode))
+ {
+ inode->i_mode = sf_g->dmode != ~0 ? (sf_g->dmode & 0777) : mode;
+ inode->i_mode &= ~sf_g->dmask;
+ inode->i_mode |= S_IFDIR;
+ inode->i_op = &sf_dir_iops;
+ inode->i_fop = &sf_dir_fops;
+ /* XXX: this probably should be set to the number of entries
+ in the directory plus two (. ..) */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+ set_nlink(inode, 1);
+#else
+ inode->i_nlink = 1;
+#endif
+ }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+ else if (RTFS_IS_SYMLINK(attr->fMode))
+ {
+ inode->i_mode = sf_g->fmode != ~0 ? (sf_g->fmode & 0777): mode;
+ inode->i_mode &= ~sf_g->fmask;
+ inode->i_mode |= S_IFLNK;
+ inode->i_op = &sf_lnk_iops;
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+ set_nlink(inode, 1);
+# else
+ inode->i_nlink = 1;
+# endif
+ }
+#endif
+ else
+ {
+ inode->i_mode = sf_g->fmode != ~0 ? (sf_g->fmode & 0777): mode;
+ inode->i_mode &= ~sf_g->fmask;
+ inode->i_mode |= S_IFREG;
+ inode->i_op = &sf_reg_iops;
+ inode->i_fop = &sf_reg_fops;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+ set_nlink(inode, 1);
+#else
+ inode->i_nlink = 1;
+#endif
+ }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+ inode->i_uid = make_kuid(current_user_ns(), sf_g->uid);
+ inode->i_gid = make_kgid(current_user_ns(), sf_g->gid);
+#else
+ inode->i_uid = sf_g->uid;
+ inode->i_gid = sf_g->gid;
+#endif
+
+ inode->i_size = info->cbObject;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) && !defined(KERNEL_FC6)
+ inode->i_blksize = 4096;
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 11)
+ inode->i_blkbits = 12;
+#endif
+ /* i_blocks always in units of 512 bytes! */
+ inode->i_blocks = (info->cbAllocated + 511) / 512;
+
+ sf_ftime_from_timespec(&inode->i_atime, &info->AccessTime);
+ sf_ftime_from_timespec(&inode->i_ctime, &info->ChangeTime);
+ sf_ftime_from_timespec(&inode->i_mtime, &info->ModificationTime);
+}
+
+int sf_stat(const char *caller, struct sf_glob_info *sf_g,
+ SHFLSTRING *path, PSHFLFSOBJINFO result, int ok_to_fail)
+{
+ int rc;
+ SHFLCREATEPARMS params;
+ NOREF(caller);
+
+ TRACE();
+
+ RT_ZERO(params);
+ params.Handle = SHFL_HANDLE_NIL;
+ params.CreateFlags = SHFL_CF_LOOKUP | SHFL_CF_ACT_FAIL_IF_NEW;
+ LogFunc(("sf_stat: calling VbglR0SfCreate, file %s, flags %#x\n",
+ path->String.utf8, params.CreateFlags));
+ rc = VbglR0SfCreate(&client_handle, &sf_g->map, path, ¶ms);
+ if (rc == VERR_INVALID_NAME)
+ {
+ /* this can happen for names like 'foo*' on a Windows host */
+ return -ENOENT;
+ }
+ if (RT_FAILURE(rc))
+ {
+ LogFunc(("VbglR0SfCreate(%s) failed. caller=%s, rc=%Rrc\n",
+ path->String.utf8, rc, caller));
+ return -EPROTO;
+ }
+ if (params.Result != SHFL_FILE_EXISTS)
+ {
+ if (!ok_to_fail)
+ LogFunc(("VbglR0SfCreate(%s) file does not exist. caller=%s, result=%d\n",
+ path->String.utf8, params.Result, caller));
+ return -ENOENT;
+ }
+
+ *result = params.Info;
+ return 0;
+}
+
+/* this is called directly as iop on 2.4, indirectly as dop
+ [sf_dentry_revalidate] on 2.4/2.6, indirectly as iop through
+ [sf_getattr] on 2.6. the job is to find out whether dentry/inode is
+ still valid. the test is failed if [dentry] does not have an inode
+ or [sf_stat] is unsuccessful, otherwise we return success and
+ update inode attributes */
+int sf_inode_revalidate(struct dentry *dentry)
+{
+ int err;
+ struct sf_glob_info *sf_g;
+ struct sf_inode_info *sf_i;
+ SHFLFSOBJINFO info;
+
+ TRACE();
+ if (!dentry || !dentry->d_inode)
+ {
+ LogFunc(("no dentry(%p) or inode(%p)\n", dentry, dentry->d_inode));
+ return -EINVAL;
+ }
+
+ sf_g = GET_GLOB_INFO(dentry->d_inode->i_sb);
+ sf_i = GET_INODE_INFO(dentry->d_inode);
+
+#if 0
+ printk("%s called by %p:%p\n",
+ sf_i->path->String.utf8,
+ __builtin_return_address (0),
+ __builtin_return_address (1));
+#endif
+
+ BUG_ON(!sf_g);
+ BUG_ON(!sf_i);
+
+ if (!sf_i->force_restat)
+ {
+ if (jiffies - dentry->d_time < sf_g->ttl)
+ return 0;
+ }
+
+ err = sf_stat(__func__, sf_g, sf_i->path, &info, 1);
+ if (err)
+ return err;
+
+ dentry->d_time = jiffies;
+ sf_init_inode(sf_g, dentry->d_inode, &info);
+ return 0;
+}
+
+/* this is called during name resolution/lookup to check if the
+ [dentry] in the cache is still valid. the job is handled by
+ [sf_inode_revalidate] */
+static int
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+sf_dentry_revalidate(struct dentry *dentry, unsigned flags)
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+sf_dentry_revalidate(struct dentry *dentry, struct nameidata *nd)
+#else
+sf_dentry_revalidate(struct dentry *dentry, int flags)
+#endif
+{
+ TRACE();
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+ if (flags & LOOKUP_RCU)
+ return -ECHILD;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
+ /* see Documentation/filesystems/vfs.txt */
+ if (nd && nd->flags & LOOKUP_RCU)
+ return -ECHILD;
+#endif
+
+ if (sf_inode_revalidate(dentry))
+ return 0;
+
+ return 1;
+}
+
+/* on 2.6 this is a proxy for [sf_inode_revalidate] which (as a side
+ effect) updates inode attributes for [dentry] (given that [dentry]
+ has inode at all) from these new attributes we derive [kstat] via
+ [generic_fillattr] */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+int sf_getattr(const struct path *path, struct kstat *kstat, u32 request_mask, unsigned int flags)
+# else
+int sf_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *kstat)
+# endif
+{
+ int err;
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+ struct dentry *dentry = path->dentry;
+# endif
+
+ TRACE();
+ err = sf_inode_revalidate(dentry);
+ if (err)
+ return err;
+
+ generic_fillattr(dentry->d_inode, kstat);
+ return 0;
+}
+
+int sf_setattr(struct dentry *dentry, struct iattr *iattr)
+{
+ struct sf_glob_info *sf_g;
+ struct sf_inode_info *sf_i;
+ SHFLCREATEPARMS params;
+ SHFLFSOBJINFO info;
+ uint32_t cbBuffer;
+ int rc, err;
+
+ TRACE();
+
+ sf_g = GET_GLOB_INFO(dentry->d_inode->i_sb);
+ sf_i = GET_INODE_INFO(dentry->d_inode);
+ err = 0;
+
+ RT_ZERO(params);
+ params.Handle = SHFL_HANDLE_NIL;
+ params.CreateFlags = SHFL_CF_ACT_OPEN_IF_EXISTS
+ | SHFL_CF_ACT_FAIL_IF_NEW
+ | SHFL_CF_ACCESS_ATTR_WRITE;
+
+ /* this is at least required for Posix hosts */
+ if (iattr->ia_valid & ATTR_SIZE)
+ params.CreateFlags |= SHFL_CF_ACCESS_WRITE;
+
+ rc = VbglR0SfCreate(&client_handle, &sf_g->map, sf_i->path, ¶ms);
+ if (RT_FAILURE(rc))
+ {
+ LogFunc(("VbglR0SfCreate(%s) failed rc=%Rrc\n",
+ sf_i->path->String.utf8, rc));
+ err = -RTErrConvertToErrno(rc);
+ goto fail2;
+ }
+ if (params.Result != SHFL_FILE_EXISTS)
+ {
+ LogFunc(("file %s does not exist\n", sf_i->path->String.utf8));
+ err = -ENOENT;
+ goto fail1;
+ }
+
+ /* Setting the file size and setting the other attributes has to be
+ * handled separately, see implementation of vbsfSetFSInfo() in
+ * vbsf.cpp */
+ if (iattr->ia_valid & (ATTR_MODE | ATTR_ATIME | ATTR_MTIME))
+ {
+#define mode_set(r) ((iattr->ia_mode & (S_##r)) ? RTFS_UNIX_##r : 0)
+
+ RT_ZERO(info);
+ if (iattr->ia_valid & ATTR_MODE)
+ {
+ info.Attr.fMode = mode_set(ISUID);
+ info.Attr.fMode |= mode_set(ISGID);
+ info.Attr.fMode |= mode_set(IRUSR);
+ info.Attr.fMode |= mode_set(IWUSR);
+ info.Attr.fMode |= mode_set(IXUSR);
+ info.Attr.fMode |= mode_set(IRGRP);
+ info.Attr.fMode |= mode_set(IWGRP);
+ info.Attr.fMode |= mode_set(IXGRP);
+ info.Attr.fMode |= mode_set(IROTH);
+ info.Attr.fMode |= mode_set(IWOTH);
+ info.Attr.fMode |= mode_set(IXOTH);
+
+ if (iattr->ia_mode & S_IFDIR)
+ info.Attr.fMode |= RTFS_TYPE_DIRECTORY;
+ else
+ info.Attr.fMode |= RTFS_TYPE_FILE;
+ }
+
+ if (iattr->ia_valid & ATTR_ATIME)
+ sf_timespec_from_ftime(&info.AccessTime, &iattr->ia_atime);
+ if (iattr->ia_valid & ATTR_MTIME)
+ sf_timespec_from_ftime(&info.ModificationTime, &iattr->ia_mtime);
+ /* ignore ctime (inode change time) as it can't be set from userland anyway */
+
+ cbBuffer = sizeof(info);
+ rc = VbglR0SfFsInfo(&client_handle, &sf_g->map, params.Handle,
+ SHFL_INFO_SET | SHFL_INFO_FILE, &cbBuffer,
+ (PSHFLDIRINFO)&info);
+ if (RT_FAILURE(rc))
+ {
+ LogFunc(("VbglR0SfFsInfo(%s, FILE) failed rc=%Rrc\n",
+ sf_i->path->String.utf8, rc));
+ err = -RTErrConvertToErrno(rc);
+ goto fail1;
+ }
+ }
+
+ if (iattr->ia_valid & ATTR_SIZE)
+ {
+ RT_ZERO(info);
+ info.cbObject = iattr->ia_size;
+ cbBuffer = sizeof(info);
+ rc = VbglR0SfFsInfo(&client_handle, &sf_g->map, params.Handle,
+ SHFL_INFO_SET | SHFL_INFO_SIZE, &cbBuffer,
+ (PSHFLDIRINFO)&info);
+ if (RT_FAILURE(rc))
+ {
+ LogFunc(("VbglR0SfFsInfo(%s, SIZE) failed rc=%Rrc\n",
+ sf_i->path->String.utf8, rc));
+ err = -RTErrConvertToErrno(rc);
+ goto fail1;
+ }
+ }
+
+ rc = VbglR0SfClose(&client_handle, &sf_g->map, params.Handle);
+ if (RT_FAILURE(rc))
+ LogFunc(("VbglR0SfClose(%s) failed rc=%Rrc\n", sf_i->path->String.utf8, rc));
+
+ return sf_inode_revalidate(dentry);
+
+fail1:
+ rc = VbglR0SfClose(&client_handle, &sf_g->map, params.Handle);
+ if (RT_FAILURE(rc))
+ LogFunc(("VbglR0SfClose(%s) failed rc=%Rrc\n", sf_i->path->String.utf8, rc));
+
+fail2:
+ return err;
+}
+#endif /* >= 2.6.0 */
+
+static int sf_make_path(const char *caller, struct sf_inode_info *sf_i,
+ const char *d_name, size_t d_len, SHFLSTRING **result)
+{
+ size_t path_len, shflstring_len;
+ SHFLSTRING *tmp;
+ uint16_t p_len;
+ uint8_t *p_name;
+ int fRoot = 0;
+
+ TRACE();
+ p_len = sf_i->path->u16Length;
+ p_name = sf_i->path->String.utf8;
+
+ if (p_len == 1 && *p_name == '/')
+ {
+ path_len = d_len + 1;
+ fRoot = 1;
+ }
+ else
+ {
+ /* lengths of constituents plus terminating zero plus slash */
+ path_len = p_len + d_len + 2;
+ if (path_len > 0xffff)
+ {
+ LogFunc(("path too long. caller=%s, path_len=%zu\n", caller, path_len));
+ return -ENAMETOOLONG;
+ }
+ }
+
+ shflstring_len = offsetof(SHFLSTRING, String.utf8) + path_len;
+ tmp = kmalloc(shflstring_len, GFP_KERNEL);
+ if (!tmp)
+ {
+ LogRelFunc(("kmalloc failed, caller=%s\n", caller));
+ return -ENOMEM;
+ }
+ tmp->u16Length = path_len - 1;
+ tmp->u16Size = path_len;
+
+ if (fRoot)
+ memcpy(&tmp->String.utf8[0], d_name, d_len + 1);
+ else
+ {
+ memcpy(&tmp->String.utf8[0], p_name, p_len);
+ tmp->String.utf8[p_len] = '/';
+ memcpy(&tmp->String.utf8[p_len + 1], d_name, d_len);
+ tmp->String.utf8[p_len + 1 + d_len] = '\0';
+ }
+
+ *result = tmp;
+ return 0;
+}
+
+/**
+ * [dentry] contains string encoded in coding system that corresponds
+ * to [sf_g]->nls, we must convert it to UTF8 here and pass down to
+ * [sf_make_path] which will allocate SHFLSTRING and fill it in
+ */
+int sf_path_from_dentry(const char *caller, struct sf_glob_info *sf_g,
+ struct sf_inode_info *sf_i, struct dentry *dentry,
+ SHFLSTRING **result)
+{
+ int err;
+ const char *d_name;
+ size_t d_len;
+ const char *name;
+ size_t len = 0;
+
+ TRACE();
+ d_name = dentry->d_name.name;
+ d_len = dentry->d_name.len;
+
+ if (sf_g->nls)
+ {
+ size_t in_len, i, out_bound_len;
+ const char *in;
+ char *out;
+
+ in = d_name;
+ in_len = d_len;
+
+ out_bound_len = PATH_MAX;
+ out = kmalloc(out_bound_len, GFP_KERNEL);
+ name = out;
+
+ for (i = 0; i < d_len; ++i)
+ {
+ /* We renamed the linux kernel wchar_t type to linux_wchar_t in
+ the-linux-kernel.h, as it conflicts with the C++ type of that name. */
+ linux_wchar_t uni;
+ int nb;
+
+ nb = sf_g->nls->char2uni(in, in_len, &uni);
+ if (nb < 0)
+ {
+ LogFunc(("nls->char2uni failed %x %d\n",
+ *in, in_len));
+ err = -EINVAL;
+ goto fail1;
+ }
+ in_len -= nb;
+ in += nb;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)
+ nb = utf32_to_utf8(uni, out, out_bound_len);
+#else
+ nb = utf8_wctomb(out, uni, out_bound_len);
+#endif
+ if (nb < 0)
+ {
+ LogFunc(("nls->uni2char failed %x %d\n",
+ uni, out_bound_len));
+ err = -EINVAL;
+ goto fail1;
+ }
+ out_bound_len -= nb;
+ out += nb;
+ len += nb;
+ }
+ if (len >= PATH_MAX - 1)
+ {
+ err = -ENAMETOOLONG;
+ goto fail1;
+ }
+
+ LogFunc(("result(%d) = %.*s\n", len, len, name));
+ *out = 0;
+ }
+ else
+ {
+ name = d_name;
+ len = d_len;
+ }
+
+ err = sf_make_path(caller, sf_i, name, len, result);
+ if (name != d_name)
+ kfree(name);
+
+ return err;
+
+fail1:
+ kfree(name);
+ return err;
+}
+
+int sf_nlscpy(struct sf_glob_info *sf_g,
+ char *name, size_t name_bound_len,
+ const unsigned char *utf8_name, size_t utf8_len)
+{
+ if (sf_g->nls)
+ {
+ const char *in;
+ char *out;
+ size_t out_len;
+ size_t out_bound_len;
+ size_t in_bound_len;
+
+ in = utf8_name;
+ in_bound_len = utf8_len;
+
+ out = name;
+ out_len = 0;
+ out_bound_len = name_bound_len;
+
+ while (in_bound_len)
+ {
+ int nb;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)
+ unicode_t uni;
+
+ nb = utf8_to_utf32(in, in_bound_len, &uni);
+#else
+ linux_wchar_t uni;
+
+ nb = utf8_mbtowc(&uni, in, in_bound_len);
+#endif
+ if (nb < 0)
+ {
+ LogFunc(("utf8_mbtowc failed(%s) %x:%d\n",
+ (const char *) utf8_name, *in, in_bound_len));
+ return -EINVAL;
+ }
+ in += nb;
+ in_bound_len -= nb;
+
+ nb = sf_g->nls->uni2char(uni, out, out_bound_len);
+ if (nb < 0)
+ {
+ LogFunc(("nls->uni2char failed(%s) %x:%d\n",
+ utf8_name, uni, out_bound_len));
+ return nb;
+ }
+ out += nb;
+ out_bound_len -= nb;
+ out_len += nb;
+ }
+
+ *out = 0;
+ }
+ else
+ {
+ if (utf8_len + 1 > name_bound_len)
+ return -ENAMETOOLONG;
+
+ memcpy(name, utf8_name, utf8_len + 1);
+ }
+ return 0;
+}
+
+static struct sf_dir_buf *sf_dir_buf_alloc(void)
+{
+ struct sf_dir_buf *b;
+
+ TRACE();
+ b = kmalloc(sizeof(*b), GFP_KERNEL);
+ if (!b)
+ {
+ LogRelFunc(("could not alloc directory buffer\n"));
+ return NULL;
+ }
+
+#ifdef USE_VMALLOC
+ b->buf = vmalloc(DIR_BUFFER_SIZE);
+#else
+ b->buf = kmalloc(DIR_BUFFER_SIZE, GFP_KERNEL);
+#endif
+ if (!b->buf)
+ {
+ kfree(b);
+ LogRelFunc(("could not alloc directory buffer storage\n"));
+ return NULL;
+ }
+
+ INIT_LIST_HEAD(&b->head);
+ b->cEntries = 0;
+ b->cbUsed = 0;
+ b->cbFree = DIR_BUFFER_SIZE;
+ return b;
+}
+
+static void sf_dir_buf_free(struct sf_dir_buf *b)
+{
+ BUG_ON(!b || !b->buf);
+
+ TRACE();
+ list_del(&b->head);
+#ifdef USE_VMALLOC
+ vfree(b->buf);
+#else
+ kfree(b->buf);
+#endif
+ kfree(b);
+}
+
+/**
+ * Free the directory buffer.
+ */
+void sf_dir_info_free(struct sf_dir_info *p)
+{
+ struct list_head *list, *pos, *tmp;
+
+ TRACE();
+ list = &p->info_list;
+ list_for_each_safe(pos, tmp, list)
+ {
+ struct sf_dir_buf *b;
+
+ b = list_entry(pos, struct sf_dir_buf, head);
+ sf_dir_buf_free(b);
+ }
+ kfree(p);
+}
+
+/**
+ * Empty (but not free) the directory buffer.
+ */
+void sf_dir_info_empty(struct sf_dir_info *p)
+{
+ struct list_head *list, *pos, *tmp;
+ TRACE();
+ list = &p->info_list;
+ list_for_each_safe(pos, tmp, list)
+ {
+ struct sf_dir_buf *b;
+ b = list_entry(pos, struct sf_dir_buf, head);
+ b->cEntries = 0;
+ b->cbUsed = 0;
+ b->cbFree = DIR_BUFFER_SIZE;
+ }
+}
+
+/**
+ * Create a new directory buffer descriptor.
+ */
+struct sf_dir_info *sf_dir_info_alloc(void)
+{
+ struct sf_dir_info *p;
+
+ TRACE();
+ p = kmalloc(sizeof(*p), GFP_KERNEL);
+ if (!p)
+ {
+ LogRelFunc(("could not alloc directory info\n"));
+ return NULL;
+ }
+
+ INIT_LIST_HEAD(&p->info_list);
+ return p;
+}
+
+/**
+ * Search for an empty directory content buffer.
+ */
+static struct sf_dir_buf *sf_get_empty_dir_buf(struct sf_dir_info *sf_d)
+{
+ struct list_head *list, *pos;
+
+ list = &sf_d->info_list;
+ list_for_each(pos, list)
+ {
+ struct sf_dir_buf *b;
+
+ b = list_entry(pos, struct sf_dir_buf, head);
+ if (!b)
+ return NULL;
+ else
+ {
+ if (b->cbUsed == 0)
+ return b;
+ }
+ }
+
+ return NULL;
+}
+
+int sf_dir_read_all(struct sf_glob_info *sf_g, struct sf_inode_info *sf_i,
+ struct sf_dir_info *sf_d, SHFLHANDLE handle)
+{
+ int err;
+ SHFLSTRING *mask;
+ struct sf_dir_buf *b;
+
+ TRACE();
+ err = sf_make_path(__func__, sf_i, "*", 1, &mask);
+ if (err)
+ goto fail0;
+
+ for (;;)
+ {
+ int rc;
+ void *buf;
+ uint32_t cbSize;
+ uint32_t cEntries;
+
+ b = sf_get_empty_dir_buf(sf_d);
+ if (!b)
+ {
+ b = sf_dir_buf_alloc();
+ if (!b)
+ {
+ err = -ENOMEM;
+ LogRelFunc(("could not alloc directory buffer\n"));
+ goto fail1;
+ }
+ list_add(&b->head, &sf_d->info_list);
+ }
+
+ buf = b->buf;
+ cbSize = b->cbFree;
+
+ rc = VbglR0SfDirInfo(&client_handle, &sf_g->map, handle, mask,
+ 0, 0, &cbSize, buf, &cEntries);
+ switch (rc)
+ {
+ case VINF_SUCCESS:
+ /* fallthrough */
+ case VERR_NO_MORE_FILES:
+ break;
+ case VERR_NO_TRANSLATION:
+ LogFunc(("host could not translate entry\n"));
+ /* XXX */
+ break;
+ default:
+ err = -RTErrConvertToErrno(rc);
+ LogFunc(("VbglR0SfDirInfo failed rc=%Rrc\n", rc));
+ goto fail1;
+ }
+
+ b->cEntries += cEntries;
+ b->cbFree -= cbSize;
+ b->cbUsed += cbSize;
+
+ if (RT_FAILURE(rc))
+ break;
+ }
+ err = 0;
+
+fail1:
+ kfree(mask);
+
+fail0:
+ return err;
+}
+
+int sf_get_volume_info(struct super_block *sb, STRUCT_STATFS *stat)
+{
+ struct sf_glob_info *sf_g;
+ SHFLVOLINFO SHFLVolumeInfo;
+ uint32_t cbBuffer;
+ int rc;
+
+ sf_g = GET_GLOB_INFO(sb);
+ cbBuffer = sizeof(SHFLVolumeInfo);
+ rc = VbglR0SfFsInfo(&client_handle, &sf_g->map, 0, SHFL_INFO_GET | SHFL_INFO_VOLUME,
+ &cbBuffer, (PSHFLDIRINFO)&SHFLVolumeInfo);
+ if (RT_FAILURE(rc))
+ return -RTErrConvertToErrno(rc);
+
+ stat->f_type = NFS_SUPER_MAGIC; /* XXX vboxsf type? */
+ stat->f_bsize = SHFLVolumeInfo.ulBytesPerAllocationUnit;
+ stat->f_blocks = SHFLVolumeInfo.ullTotalAllocationBytes
+ / SHFLVolumeInfo.ulBytesPerAllocationUnit;
+ stat->f_bfree = SHFLVolumeInfo.ullAvailableAllocationBytes
+ / SHFLVolumeInfo.ulBytesPerAllocationUnit;
+ stat->f_bavail = SHFLVolumeInfo.ullAvailableAllocationBytes
+ / SHFLVolumeInfo.ulBytesPerAllocationUnit;
+ stat->f_files = 1000;
+ stat->f_ffree = 1000; /* don't return 0 here since the guest may think
+ * that it is not possible to create any more files */
+ stat->f_fsid.val[0] = 0;
+ stat->f_fsid.val[1] = 0;
+ stat->f_namelen = 255;
+ return 0;
+}
+
+struct dentry_operations sf_dentry_ops =
+{
+ .d_revalidate = sf_dentry_revalidate
+};
+
+int sf_init_backing_dev(struct sf_glob_info *sf_g)
+{
+ int rc = 0;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) && LINUX_VERSION_CODE <= KERNEL_VERSION(3, 19, 0)
+ /* Each new shared folder map gets a new uint64_t identifier,
+ * allocated in sequence. We ASSUME the sequence will not wrap. */
+ static uint64_t s_u64Sequence = 0;
+ uint64_t u64CurrentSequence = ASMAtomicIncU64(&s_u64Sequence);
+
+ sf_g->bdi.ra_pages = 0; /* No readahead */
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12)
+ sf_g->bdi.capabilities = BDI_CAP_MAP_DIRECT /* MAP_SHARED */
+ | BDI_CAP_MAP_COPY /* MAP_PRIVATE */
+ | BDI_CAP_READ_MAP /* can be mapped for reading */
+ | BDI_CAP_WRITE_MAP /* can be mapped for writing */
+ | BDI_CAP_EXEC_MAP; /* can be mapped for execution */
+# endif /* >= 2.6.12 */
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
+ rc = bdi_init(&sf_g->bdi);
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ if (!rc)
+ rc = bdi_register(&sf_g->bdi, NULL, "vboxsf-%llu",
+ (unsigned long long)u64CurrentSequence);
+# endif /* >= 2.6.26 */
+# endif /* >= 2.6.24 */
+#endif /* >= 2.6.0 && <= 3.19.0 */
+ return rc;
+}
+
+void sf_done_backing_dev(struct sf_glob_info *sf_g)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) && LINUX_VERSION_CODE <= KERNEL_VERSION(3, 19, 0)
+ bdi_destroy(&sf_g->bdi); /* includes bdi_unregister() */
+#endif
+}
--- /dev/null
+/** @file
+ * vboxsf -- VirtualBox Guest Additions for Linux: mount(2) parameter structure.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef VBFS_MOUNT_H
+#define VBFS_MOUNT_H
+
+#define MAX_HOST_NAME 256
+#define MAX_NLS_NAME 32
+
+/* Linux constraints the size of data mount argument to PAGE_SIZE - 1. */
+struct vbsf_mount_info_old
+{
+ char name[MAX_HOST_NAME];
+ char nls_name[MAX_NLS_NAME];
+ int uid;
+ int gid;
+ int ttl;
+};
+
+#define VBSF_MOUNT_SIGNATURE_BYTE_0 '\377'
+#define VBSF_MOUNT_SIGNATURE_BYTE_1 '\376'
+#define VBSF_MOUNT_SIGNATURE_BYTE_2 '\375'
+
+struct vbsf_mount_info_new
+{
+ char nullchar; /* name cannot be '\0' -- we use this field
+ to distinguish between the old structure
+ and the new structure */
+ char signature[3]; /* signature */
+ int length; /* length of the whole structure */
+ char name[MAX_HOST_NAME]; /* share name */
+ char nls_name[MAX_NLS_NAME];/* name of an I/O charset */
+ int uid; /* user ID for all entries, default 0=root */
+ int gid; /* group ID for all entries, default 0=root */
+ int ttl; /* time to live */
+ int dmode; /* mode for directories if != 0xffffffff */
+ int fmode; /* mode for regular files if != 0xffffffff */
+ int dmask; /* umask applied to directories */
+ int fmask; /* umask applied to regular files */
+};
+
+struct vbsf_mount_opts
+{
+ int uid;
+ int gid;
+ int ttl;
+ int dmode;
+ int fmode;
+ int dmask;
+ int fmask;
+ int ronly;
+ int sloppy;
+ int noexec;
+ int nodev;
+ int nosuid;
+ int remount;
+ char nls_name[MAX_NLS_NAME];
+ char *convertcp;
+};
+
+/** Completes the mount operation by adding the new mount point to mtab if required. */
+int vbsfmount_complete(const char *host_name, const char *mount_point,
+ unsigned long flags, struct vbsf_mount_opts *opts);
+
+#endif /* vbsfmount.h */
--- /dev/null
+#ifndef ___version_generated_h___
+#define ___version_generated_h___
+
+#define VBOX_VERSION_MAJOR 5
+#define VBOX_VERSION_MINOR 1
+#define VBOX_VERSION_BUILD 28
+#define VBOX_VERSION_STRING_RAW "5.1.28"
+#define VBOX_VERSION_STRING "5.1.28_Ubuntu"
+#define VBOX_API_VERSION_STRING "5_1"
+
+#define VBOX_PRIVATE_BUILD_DESC "Private build by buildd"
+
+#endif
--- /dev/null
+/** @file
+ *
+ * vboxsf -- VirtualBox Guest Additions for Linux:
+ * Virtual File System for VirtualBox Shared Folders
+ *
+ * Module initialization/finalization
+ * File system registration/deregistration
+ * Superblock reading
+ * Few utility functions
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/**
+ * @note Anyone wishing to make changes here might wish to take a look at
+ * http://www.atnf.csiro.au/people/rgooch/linux/vfs.txt
+ * which seems to be the closest there is to official documentation on
+ * writing filesystem drivers for Linux.
+ */
+
+#include "vfsmod.h"
+#include "version-generated.h"
+#include "revision-generated.h"
+#include "product-generated.h"
+
+MODULE_DESCRIPTION(VBOX_PRODUCT " VFS Module for Host File System Access");
+MODULE_AUTHOR(VBOX_VENDOR);
+MODULE_LICENSE("GPL");
+#ifdef MODULE_ALIAS_FS
+MODULE_ALIAS_FS("vboxsf");
+#endif
+#ifdef MODULE_VERSION
+MODULE_VERSION(VBOX_VERSION_STRING " r" RT_XSTR(VBOX_SVN_REV));
+#endif
+
+/* globals */
+VBGLSFCLIENT client_handle;
+
+/* forward declarations */
+static struct super_operations sf_super_ops;
+
+/* allocate global info, try to map host share */
+static int sf_glob_alloc(struct vbsf_mount_info_new *info, struct sf_glob_info **sf_gp)
+{
+ int err, rc;
+ SHFLSTRING *str_name;
+ size_t name_len, str_len;
+ struct sf_glob_info *sf_g;
+
+ TRACE();
+ sf_g = kmalloc(sizeof(*sf_g), GFP_KERNEL);
+ if (!sf_g)
+ {
+ err = -ENOMEM;
+ LogRelFunc(("could not allocate memory for global info\n"));
+ goto fail0;
+ }
+
+ RT_ZERO(*sf_g);
+
+ if ( info->nullchar != '\0'
+ || info->signature[0] != VBSF_MOUNT_SIGNATURE_BYTE_0
+ || info->signature[1] != VBSF_MOUNT_SIGNATURE_BYTE_1
+ || info->signature[2] != VBSF_MOUNT_SIGNATURE_BYTE_2)
+ {
+ /* An old version of mount.vboxsf made the syscall. Translate the
+ * old parameters to the new structure. */
+ struct vbsf_mount_info_old *info_old = (struct vbsf_mount_info_old *)info;
+ static struct vbsf_mount_info_new info_compat;
+
+ info = &info_compat;
+ memset(info, 0, sizeof(*info));
+ memcpy(&info->name, &info_old->name, MAX_HOST_NAME);
+ memcpy(&info->nls_name, &info_old->nls_name, MAX_NLS_NAME);
+ info->length = offsetof(struct vbsf_mount_info_new, dmode);
+ info->uid = info_old->uid;
+ info->gid = info_old->gid;
+ info->ttl = info_old->ttl;
+ }
+
+ info->name[sizeof(info->name) - 1] = 0;
+ info->nls_name[sizeof(info->nls_name) - 1] = 0;
+
+ name_len = strlen(info->name);
+ if (name_len > 0xfffe)
+ {
+ err = -ENAMETOOLONG;
+ LogFunc(("map name too big\n"));
+ goto fail1;
+ }
+
+ str_len = offsetof(SHFLSTRING, String.utf8) + name_len + 1;
+ str_name = kmalloc(str_len, GFP_KERNEL);
+ if (!str_name)
+ {
+ err = -ENOMEM;
+ LogRelFunc(("could not allocate memory for host name\n"));
+ goto fail1;
+ }
+
+ str_name->u16Length = name_len;
+ str_name->u16Size = name_len + 1;
+ memcpy(str_name->String.utf8, info->name, name_len + 1);
+
+#define _IS_UTF8(_str) \
+ (strcmp(_str, "utf8") == 0)
+#define _IS_EMPTY(_str) \
+ (strcmp(_str, "") == 0)
+
+ /* Check if NLS charset is valid and not points to UTF8 table */
+ if (info->nls_name[0])
+ {
+ if (_IS_UTF8(info->nls_name))
+ sf_g->nls = NULL;
+ else
+ {
+ sf_g->nls = load_nls(info->nls_name);
+ if (!sf_g->nls)
+ {
+ err = -EINVAL;
+ LogFunc(("failed to load nls %s\n", info->nls_name));
+ kfree(str_name);
+ goto fail1;
+ }
+ }
+ }
+ else
+ {
+#ifdef CONFIG_NLS_DEFAULT
+ /* If no NLS charset specified, try to load the default
+ * one if it's not points to UTF8. */
+ if (!_IS_UTF8(CONFIG_NLS_DEFAULT) && !_IS_EMPTY(CONFIG_NLS_DEFAULT))
+ sf_g->nls = load_nls_default();
+ else
+ sf_g->nls = NULL;
+#else
+ sf_g->nls = NULL;
+#endif
+
+#undef _IS_UTF8
+#undef _IS_EMPTY
+ }
+
+ rc = VbglR0SfMapFolder(&client_handle, str_name, &sf_g->map);
+ kfree(str_name);
+
+ if (RT_FAILURE(rc))
+ {
+ err = -EPROTO;
+ LogFunc(("VbglR0SfMapFolder failed rc=%d\n", rc));
+ goto fail2;
+ }
+
+ sf_g->ttl = info->ttl;
+ sf_g->uid = info->uid;
+ sf_g->gid = info->gid;
+
+ if ((unsigned)info->length >= sizeof(struct vbsf_mount_info_new))
+ {
+ /* new fields */
+ sf_g->dmode = info->dmode;
+ sf_g->fmode = info->fmode;
+ sf_g->dmask = info->dmask;
+ sf_g->fmask = info->fmask;
+ }
+ else
+ {
+ sf_g->dmode = ~0;
+ sf_g->fmode = ~0;
+ }
+
+ *sf_gp = sf_g;
+ return 0;
+
+fail2:
+ if (sf_g->nls)
+ unload_nls(sf_g->nls);
+
+fail1:
+ kfree(sf_g);
+
+fail0:
+ return err;
+}
+
+/* unmap the share and free global info [sf_g] */
+static void
+sf_glob_free(struct sf_glob_info *sf_g)
+{
+ int rc;
+
+ TRACE();
+ rc = VbglR0SfUnmapFolder(&client_handle, &sf_g->map);
+ if (RT_FAILURE(rc))
+ LogFunc(("VbglR0SfUnmapFolder failed rc=%d\n", rc));
+
+ if (sf_g->nls)
+ unload_nls(sf_g->nls);
+
+ kfree(sf_g);
+}
+
+/**
+ * This is called (by sf_read_super_[24|26] when vfs mounts the fs and
+ * wants to read super_block.
+ *
+ * calls [sf_glob_alloc] to map the folder and allocate global
+ * information structure.
+ *
+ * initializes [sb], initializes root inode and dentry.
+ *
+ * should respect [flags]
+ */
+static int sf_read_super_aux(struct super_block *sb, void *data, int flags)
+{
+ int err;
+ struct dentry *droot;
+ struct inode *iroot;
+ struct sf_inode_info *sf_i;
+ struct sf_glob_info *sf_g;
+ SHFLFSOBJINFO fsinfo;
+ struct vbsf_mount_info_new *info;
+ bool fInodePut = true;
+
+ TRACE();
+ if (!data)
+ {
+ LogFunc(("no mount info specified\n"));
+ return -EINVAL;
+ }
+
+ info = data;
+
+ if (flags & MS_REMOUNT)
+ {
+ LogFunc(("remounting is not supported\n"));
+ return -ENOSYS;
+ }
+
+ err = sf_glob_alloc(info, &sf_g);
+ if (err)
+ goto fail0;
+
+ sf_i = kmalloc(sizeof (*sf_i), GFP_KERNEL);
+ if (!sf_i)
+ {
+ err = -ENOMEM;
+ LogRelFunc(("could not allocate memory for root inode info\n"));
+ goto fail1;
+ }
+
+ sf_i->handle = SHFL_HANDLE_NIL;
+ sf_i->path = kmalloc(sizeof(SHFLSTRING) + 1, GFP_KERNEL);
+ if (!sf_i->path)
+ {
+ err = -ENOMEM;
+ LogRelFunc(("could not allocate memory for root inode path\n"));
+ goto fail2;
+ }
+
+ sf_i->path->u16Length = 1;
+ sf_i->path->u16Size = 2;
+ sf_i->path->String.utf8[0] = '/';
+ sf_i->path->String.utf8[1] = 0;
+ sf_i->force_reread = 0;
+
+ err = sf_stat(__func__, sf_g, sf_i->path, &fsinfo, 0);
+ if (err)
+ {
+ LogFunc(("could not stat root of share\n"));
+ goto fail3;
+ }
+
+ sb->s_magic = 0xface;
+ sb->s_blocksize = 1024;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 3)
+ /* Required for seek/sendfile.
+ *
+ * Must by less than or equal to INT64_MAX despite the fact that the
+ * declaration of this variable is unsigned long long. See determination
+ * of 'loff_t max' in fs/read_write.c / do_sendfile(). I don't know the
+ * correct limit but MAX_LFS_FILESIZE (8TB-1 on 32-bit boxes) takes the
+ * page cache into account and is the suggested limit. */
+# if defined MAX_LFS_FILESIZE
+ sb->s_maxbytes = MAX_LFS_FILESIZE;
+# else
+ sb->s_maxbytes = 0x7fffffffffffffffULL;
+# endif
+#endif
+ sb->s_op = &sf_super_ops;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
+ iroot = iget_locked(sb, 0);
+#else
+ iroot = iget(sb, 0);
+#endif
+ if (!iroot)
+ {
+ err = -ENOMEM; /* XXX */
+ LogFunc(("could not get root inode\n"));
+ goto fail3;
+ }
+
+ if (sf_init_backing_dev(sf_g))
+ {
+ err = -EINVAL;
+ LogFunc(("could not init bdi\n"));
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
+ unlock_new_inode(iroot);
+#endif
+ goto fail4;
+ }
+
+ sf_init_inode(sf_g, iroot, &fsinfo);
+ SET_INODE_INFO(iroot, sf_i);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
+ unlock_new_inode(iroot);
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
+ droot = d_make_root(iroot);
+#else
+ droot = d_alloc_root(iroot);
+#endif
+ if (!droot)
+ {
+ err = -ENOMEM; /* XXX */
+ LogFunc(("d_alloc_root failed\n"));
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
+ fInodePut = false;
+#endif
+ goto fail5;
+ }
+
+ sb->s_root = droot;
+ SET_GLOB_INFO(sb, sf_g);
+ return 0;
+
+fail5:
+ sf_done_backing_dev(sf_g);
+
+fail4:
+ if (fInodePut)
+ iput(iroot);
+
+fail3:
+ kfree(sf_i->path);
+
+fail2:
+ kfree(sf_i);
+
+fail1:
+ sf_glob_free(sf_g);
+
+fail0:
+ return err;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
+static struct super_block *
+sf_read_super_24(struct super_block *sb, void *data, int flags)
+{
+ int err;
+
+ TRACE();
+ err = sf_read_super_aux(sb, data, flags);
+ if (err)
+ return NULL;
+
+ return sb;
+}
+#endif
+
+/* this is called when vfs is about to destroy the [inode]. all
+ resources associated with this [inode] must be cleared here */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
+static void sf_clear_inode(struct inode *inode)
+{
+ struct sf_inode_info *sf_i;
+
+ TRACE();
+ sf_i = GET_INODE_INFO(inode);
+ if (!sf_i)
+ return;
+
+ BUG_ON(!sf_i->path);
+ kfree(sf_i->path);
+ kfree(sf_i);
+ SET_INODE_INFO(inode, NULL);
+}
+#else
+static void sf_evict_inode(struct inode *inode)
+{
+ struct sf_inode_info *sf_i;
+
+ TRACE();
+ truncate_inode_pages(&inode->i_data, 0);
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+ clear_inode(inode);
+# else
+ end_writeback(inode);
+# endif
+
+ sf_i = GET_INODE_INFO(inode);
+ if (!sf_i)
+ return;
+
+ BUG_ON(!sf_i->path);
+ kfree(sf_i->path);
+ kfree(sf_i);
+ SET_INODE_INFO(inode, NULL);
+}
+#endif
+
+/* this is called by vfs when it wants to populate [inode] with data.
+ the only thing that is known about inode at this point is its index
+ hence we can't do anything here, and let lookup/whatever with the
+ job to properly fill then [inode] */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
+static void sf_read_inode(struct inode *inode)
+{
+}
+#endif
+
+/* vfs is done with [sb] (umount called) call [sf_glob_free] to unmap
+ the folder and free [sf_g] */
+static void sf_put_super(struct super_block *sb)
+{
+ struct sf_glob_info *sf_g;
+
+ sf_g = GET_GLOB_INFO(sb);
+ BUG_ON(!sf_g);
+ sf_done_backing_dev(sf_g);
+ sf_glob_free(sf_g);
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
+static int sf_statfs(struct super_block *sb, STRUCT_STATFS *stat)
+{
+ return sf_get_volume_info(sb, stat);
+}
+#else
+static int sf_statfs(struct dentry *dentry, STRUCT_STATFS *stat)
+{
+ struct super_block *sb = dentry->d_inode->i_sb;
+ return sf_get_volume_info(sb, stat);
+}
+#endif
+
+static int sf_remount_fs(struct super_block *sb, int *flags, char *data)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 23)
+ struct sf_glob_info *sf_g;
+ struct sf_inode_info *sf_i;
+ struct inode *iroot;
+ SHFLFSOBJINFO fsinfo;
+ int err;
+
+ sf_g = GET_GLOB_INFO(sb);
+ BUG_ON(!sf_g);
+ if (data && data[0] != 0)
+ {
+ struct vbsf_mount_info_new *info =
+ (struct vbsf_mount_info_new *)data;
+ if ( info->signature[0] == VBSF_MOUNT_SIGNATURE_BYTE_0
+ && info->signature[1] == VBSF_MOUNT_SIGNATURE_BYTE_1
+ && info->signature[2] == VBSF_MOUNT_SIGNATURE_BYTE_2)
+ {
+ sf_g->uid = info->uid;
+ sf_g->gid = info->gid;
+ sf_g->ttl = info->ttl;
+ sf_g->dmode = info->dmode;
+ sf_g->fmode = info->fmode;
+ sf_g->dmask = info->dmask;
+ sf_g->fmask = info->fmask;
+ }
+ }
+
+ iroot = ilookup(sb, 0);
+ if (!iroot)
+ return -ENOSYS;
+
+ sf_i = GET_INODE_INFO(iroot);
+ err = sf_stat(__func__, sf_g, sf_i->path, &fsinfo, 0);
+ BUG_ON(err != 0);
+ sf_init_inode(sf_g, iroot, &fsinfo);
+ /*unlock_new_inode(iroot);*/
+ return 0;
+#else
+ return -ENOSYS;
+#endif
+}
+
+static struct super_operations sf_super_ops =
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
+ .clear_inode = sf_clear_inode,
+#else
+ .evict_inode = sf_evict_inode,
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
+ .read_inode = sf_read_inode,
+#endif
+ .put_super = sf_put_super,
+ .statfs = sf_statfs,
+ .remount_fs = sf_remount_fs
+};
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
+static DECLARE_FSTYPE(vboxsf_fs_type, "vboxsf", sf_read_super_24, 0);
+#else
+static int
+sf_read_super_26(struct super_block *sb, void *data, int flags)
+{
+ int err;
+
+ TRACE();
+ err = sf_read_super_aux(sb, data, flags);
+ if (err)
+ printk(KERN_DEBUG "sf_read_super_aux err=%d\n", err);
+
+ return err;
+}
+
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
+static struct super_block *sf_get_sb(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *data)
+{
+ TRACE();
+ return get_sb_nodev(fs_type, flags, data, sf_read_super_26);
+}
+# elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
+static int sf_get_sb(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *data, struct vfsmount *mnt)
+{
+ TRACE();
+ return get_sb_nodev(fs_type, flags, data, sf_read_super_26, mnt);
+}
+# else
+static struct dentry *sf_mount(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *data)
+{
+ TRACE();
+ return mount_nodev(fs_type, flags, data, sf_read_super_26);
+}
+# endif
+
+static struct file_system_type vboxsf_fs_type =
+{
+ .owner = THIS_MODULE,
+ .name = "vboxsf",
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
+ .get_sb = sf_get_sb,
+# else
+ .mount = sf_mount,
+# endif
+ .kill_sb = kill_anon_super
+};
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+static int follow_symlinks = 0;
+module_param(follow_symlinks, int, 0);
+MODULE_PARM_DESC(follow_symlinks, "Let host resolve symlinks rather than showing them");
+#endif
+
+/* Module initialization/finalization handlers */
+static int __init init(void)
+{
+ int rcVBox;
+ int rcRet = 0;
+ int err;
+
+ TRACE();
+
+ if (sizeof(struct vbsf_mount_info_new) > PAGE_SIZE)
+ {
+ printk(KERN_ERR
+ "Mount information structure is too large %lu\n"
+ "Must be less than or equal to %lu\n",
+ (unsigned long)sizeof (struct vbsf_mount_info_new),
+ (unsigned long)PAGE_SIZE);
+ return -EINVAL;
+ }
+
+ err = register_filesystem(&vboxsf_fs_type);
+ if (err)
+ {
+ LogFunc(("register_filesystem err=%d\n", err));
+ return err;
+ }
+
+ rcVBox = VbglR0SfInit();
+ if (RT_FAILURE(rcVBox))
+ {
+ LogRelFunc(("VbglR0SfInit failed, rc=%d\n", rcVBox));
+ rcRet = -EPROTO;
+ goto fail0;
+ }
+
+ rcVBox = VbglR0SfConnect(&client_handle);
+ if (RT_FAILURE(rcVBox))
+ {
+ LogRelFunc(("VbglR0SfConnect failed, rc=%d\n", rcVBox));
+ rcRet = -EPROTO;
+ goto fail1;
+ }
+
+ rcVBox = VbglR0SfSetUtf8(&client_handle);
+ if (RT_FAILURE(rcVBox))
+ {
+ LogRelFunc(("VbglR0SfSetUtf8 failed, rc=%d\n", rcVBox));
+ rcRet = -EPROTO;
+ goto fail2;
+ }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+ if (!follow_symlinks)
+ {
+ rcVBox = VbglR0SfSetSymlinks(&client_handle);
+ if (RT_FAILURE(rcVBox))
+ {
+ printk(KERN_WARNING
+ "vboxsf: Host unable to show symlinks, rc=%d\n",
+ rcVBox);
+ }
+ }
+#endif
+
+ printk(KERN_DEBUG
+ "vboxsf: Successfully loaded version " VBOX_VERSION_STRING
+ " (interface " RT_XSTR(VMMDEV_VERSION) ")\n");
+
+ return 0;
+
+fail2:
+ VbglR0SfDisconnect(&client_handle);
+
+fail1:
+ VbglR0SfTerm();
+
+fail0:
+ unregister_filesystem(&vboxsf_fs_type);
+ return rcRet;
+}
+
+static void __exit fini(void)
+{
+ TRACE();
+
+ VbglR0SfDisconnect(&client_handle);
+ VbglR0SfTerm();
+ unregister_filesystem(&vboxsf_fs_type);
+}
+
+module_init(init);
+module_exit(fini);
+
+/* C++ hack */
+int __gxx_personality_v0 = 0xdeadbeef;
--- /dev/null
+/** @file
+ * vboxsf - VirtualBox Guest Additions for Linux.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef VFSMOD_H
+#define VFSMOD_H
+
+#define LOG_GROUP LOG_GROUP_SHARED_FOLDERS
+#include "the-linux-kernel.h"
+#include <VBox/log.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+# include <linux/backing-dev.h>
+#endif
+
+#include <VBox/VBoxGuestLibSharedFolders.h>
+#include "vbsfmount.h"
+
+#define DIR_BUFFER_SIZE (16*_1K)
+
+/* per-shared folder information */
+struct sf_glob_info
+{
+ VBGLSFMAP map;
+ struct nls_table *nls;
+ int ttl;
+ int uid;
+ int gid;
+ int dmode;
+ int fmode;
+ int dmask;
+ int fmask;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+ struct backing_dev_info bdi;
+#endif
+};
+
+/* per-inode information */
+struct sf_inode_info
+{
+ /* which file */
+ SHFLSTRING *path;
+ /* some information was changed, update data on next revalidate */
+ int force_restat;
+ /* directory content changed, update the whole directory on next sf_getdent */
+ int force_reread;
+ /* file structure, only valid between open() and release() */
+ struct file *file;
+ /* handle valid if a file was created with sf_create_aux until it will
+ * be opened with sf_reg_open() */
+ SHFLHANDLE handle;
+};
+
+struct sf_dir_info
+{
+ struct list_head info_list;
+};
+
+struct sf_dir_buf
+{
+ size_t cEntries;
+ size_t cbFree;
+ size_t cbUsed;
+ void *buf;
+ struct list_head head;
+};
+
+struct sf_reg_info
+{
+ SHFLHANDLE handle;
+};
+
+/* globals */
+extern VBGLSFCLIENT client_handle;
+
+/* forward declarations */
+extern struct inode_operations sf_dir_iops;
+extern struct inode_operations sf_lnk_iops;
+extern struct inode_operations sf_reg_iops;
+extern struct file_operations sf_dir_fops;
+extern struct file_operations sf_reg_fops;
+extern struct dentry_operations sf_dentry_ops;
+extern struct address_space_operations sf_reg_aops;
+
+extern void sf_init_inode(struct sf_glob_info *sf_g, struct inode *inode,
+ PSHFLFSOBJINFO info);
+extern int sf_stat(const char *caller, struct sf_glob_info *sf_g,
+ SHFLSTRING *path, PSHFLFSOBJINFO result, int ok_to_fail);
+extern int sf_inode_revalidate(struct dentry *dentry);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+extern int sf_getattr(const struct path *path, struct kstat *kstat,
+ u32 request_mask, unsigned int query_flags);
+# else
+extern int sf_getattr(struct vfsmount *mnt, struct dentry *dentry,
+ struct kstat *kstat);
+#endif
+extern int sf_setattr(struct dentry *dentry, struct iattr *iattr);
+#endif
+extern int sf_path_from_dentry(const char *caller, struct sf_glob_info *sf_g,
+ struct sf_inode_info *sf_i, struct dentry *dentry,
+ SHFLSTRING **result);
+extern int sf_nlscpy(struct sf_glob_info *sf_g,
+ char *name, size_t name_bound_len,
+ const unsigned char *utf8_name, size_t utf8_len);
+extern void sf_dir_info_free(struct sf_dir_info *p);
+extern void sf_dir_info_empty(struct sf_dir_info *p);
+extern struct sf_dir_info *sf_dir_info_alloc(void);
+extern int sf_dir_read_all(struct sf_glob_info *sf_g, struct sf_inode_info *sf_i,
+ struct sf_dir_info *sf_d, SHFLHANDLE handle);
+extern int sf_init_backing_dev(struct sf_glob_info *sf_g);
+extern void sf_done_backing_dev(struct sf_glob_info *sf_g);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
+# define STRUCT_STATFS struct statfs
+#else
+# define STRUCT_STATFS struct kstatfs
+#endif
+int sf_get_volume_info(struct super_block *sb,STRUCT_STATFS *stat);
+
+#ifdef __cplusplus
+# define CMC_API __attribute__ ((cdecl, regparm (0)))
+#else
+# define CMC_API __attribute__ ((regparm (0)))
+#endif
+
+#define TRACE() LogFunc(("tracepoint\n"))
+
+/* Following casts are here to prevent assignment of void * to
+ pointers of arbitrary type */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
+# define GET_GLOB_INFO(sb) ((struct sf_glob_info *) (sb)->u.generic_sbp)
+# define SET_GLOB_INFO(sb, sf_g) (sb)->u.generic_sbp = sf_g
+#else
+# define GET_GLOB_INFO(sb) ((struct sf_glob_info *) (sb)->s_fs_info)
+# define SET_GLOB_INFO(sb, sf_g) (sb)->s_fs_info = sf_g
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) || defined(KERNEL_FC6)
+/* FC6 kernel 2.6.18, vanilla kernel 2.6.19+ */
+# define GET_INODE_INFO(i) ((struct sf_inode_info *) (i)->i_private)
+# define SET_INODE_INFO(i, sf_i) (i)->i_private = sf_i
+#else
+/* vanilla kernel up to 2.6.18 */
+# define GET_INODE_INFO(i) ((struct sf_inode_info *) (i)->u.generic_ip)
+# define SET_INODE_INFO(i, sf_i) (i)->u.generic_ip = sf_i
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
+# define GET_F_DENTRY(f) (f->f_path.dentry)
+#else
+# define GET_F_DENTRY(f) (f->f_dentry)
+#endif
+
+#endif
+
--- /dev/null
+/* $Id: HGSMIBase.cpp $ */
+/** @file
+ * VirtualBox Video driver, common code - HGSMI initialisation and helper
+ * functions.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include <VBox/VBoxVideoGuest.h>
+#include <VBox/VBoxVideo.h>
+#include <VBox/VBoxGuest.h>
+#include <VBox/Hardware/VBoxVideoVBE.h>
+#include <VBox/VMMDev.h>
+
+#include <iprt/asm.h>
+#include <iprt/log.h>
+#include <iprt/string.h>
+
+/** Send completion notification to the host for the command located at offset
+ * @a offt into the host command buffer. */
+static void HGSMINotifyHostCmdComplete(PHGSMIHOSTCOMMANDCONTEXT pCtx, HGSMIOFFSET offt)
+{
+ VBoxVideoCmnPortWriteUlong(pCtx->port, offt);
+}
+
+
+/**
+ * Inform the host that a command has been handled.
+ *
+ * @param pCtx the context containing the heap to be used
+ * @param pvMem pointer into the heap as mapped in @a pCtx to the command to
+ * be completed
+ */
+DECLHIDDEN(void) VBoxHGSMIHostCmdComplete(PHGSMIHOSTCOMMANDCONTEXT pCtx,
+ void *pvMem)
+{
+ HGSMIBUFFERHEADER *pHdr = HGSMIBufferHeaderFromData(pvMem);
+ HGSMIOFFSET offMem = HGSMIPointerToOffset(&pCtx->areaCtx, pHdr);
+ Assert(offMem != HGSMIOFFSET_VOID);
+ if(offMem != HGSMIOFFSET_VOID)
+ {
+ HGSMINotifyHostCmdComplete(pCtx, offMem);
+ }
+}
+
+
+/** Submit an incoming host command to the appropriate handler. */
+static void hgsmiHostCmdProcess(PHGSMIHOSTCOMMANDCONTEXT pCtx,
+ HGSMIOFFSET offBuffer)
+{
+ int rc = HGSMIBufferProcess(&pCtx->areaCtx, &pCtx->channels, offBuffer);
+ Assert(!RT_FAILURE(rc));
+ if(RT_FAILURE(rc))
+ {
+ /* failure means the command was not submitted to the handler for some reason
+ * it's our responsibility to notify its completion in this case */
+ HGSMINotifyHostCmdComplete(pCtx, offBuffer);
+ }
+ /* if the cmd succeeded it's responsibility of the callback to complete it */
+}
+
+/** Get the next command from the host. */
+static HGSMIOFFSET hgsmiGetHostBuffer(PHGSMIHOSTCOMMANDCONTEXT pCtx)
+{
+ return VBoxVideoCmnPortReadUlong(pCtx->port);
+}
+
+
+/** Get and handle the next command from the host. */
+static void hgsmiHostCommandQueryProcess(PHGSMIHOSTCOMMANDCONTEXT pCtx)
+{
+ HGSMIOFFSET offset = hgsmiGetHostBuffer(pCtx);
+ AssertReturnVoid(offset != HGSMIOFFSET_VOID);
+ hgsmiHostCmdProcess(pCtx, offset);
+}
+
+
+/** Drain the host command queue. */
+DECLHIDDEN(void) VBoxHGSMIProcessHostQueue(PHGSMIHOSTCOMMANDCONTEXT pCtx)
+{
+ while (pCtx->pfHostFlags->u32HostFlags & HGSMIHOSTFLAGS_COMMANDS_PENDING)
+ {
+ if (!ASMAtomicCmpXchgBool(&pCtx->fHostCmdProcessing, true, false))
+ return;
+ hgsmiHostCommandQueryProcess(pCtx);
+ ASMAtomicWriteBool(&pCtx->fHostCmdProcessing, false);
+ }
+}
+
+
+/** Detect whether HGSMI is supported by the host. */
+DECLHIDDEN(bool) VBoxHGSMIIsSupported(void)
+{
+ uint16_t DispiId;
+
+ VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
+ VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID_HGSMI);
+
+ DispiId = VBoxVideoCmnPortReadUshort(VBE_DISPI_IOPORT_DATA);
+
+ return (DispiId == VBE_DISPI_ID_HGSMI);
+}
+
+
+/**
+ * Allocate and initialise a command descriptor in the guest heap for a
+ * guest-to-host command.
+ *
+ * @returns pointer to the descriptor's command data buffer
+ * @param pCtx the context containing the heap to be used
+ * @param cbData the size of the command data to go into the descriptor
+ * @param u8Ch the HGSMI channel to be used, set to the descriptor
+ * @param u16Op the HGSMI command to be sent, set to the descriptor
+ */
+DECLHIDDEN(void *) VBoxHGSMIBufferAlloc(PHGSMIGUESTCOMMANDCONTEXT pCtx,
+ HGSMISIZE cbData,
+ uint8_t u8Ch,
+ uint16_t u16Op)
+{
+#ifdef VBOX_WDDM_MINIPORT
+ return VBoxSHGSMIHeapAlloc (&pCtx->heapCtx, cbData, u8Ch, u16Op);
+#else
+ return HGSMIHeapAlloc (&pCtx->heapCtx, cbData, u8Ch, u16Op);
+#endif
+}
+
+
+/**
+ * Free a descriptor allocated by @a VBoxHGSMIBufferAlloc.
+ *
+ * @param pCtx the context containing the heap used
+ * @param pvBuffer the pointer returned by @a VBoxHGSMIBufferAlloc
+ */
+DECLHIDDEN(void) VBoxHGSMIBufferFree(PHGSMIGUESTCOMMANDCONTEXT pCtx,
+ void *pvBuffer)
+{
+#ifdef VBOX_WDDM_MINIPORT
+ VBoxSHGSMIHeapFree (&pCtx->heapCtx, pvBuffer);
+#else
+ HGSMIHeapFree (&pCtx->heapCtx, pvBuffer);
+#endif
+}
+
+
+/**
+ * Submit a command descriptor allocated by @a VBoxHGSMIBufferAlloc.
+ *
+ * @param pCtx the context containing the heap used
+ * @param pvBuffer the pointer returned by @a VBoxHGSMIBufferAlloc
+ */
+DECLHIDDEN(int) VBoxHGSMIBufferSubmit(PHGSMIGUESTCOMMANDCONTEXT pCtx,
+ void *pvBuffer)
+{
+ /* Initialize the buffer and get the offset for port IO. */
+ HGSMIOFFSET offBuffer = HGSMIHeapBufferOffset (HGSMIGUESTCMDHEAP_GET(&pCtx->heapCtx), pvBuffer);
+
+ Assert(offBuffer != HGSMIOFFSET_VOID);
+ if (offBuffer != HGSMIOFFSET_VOID)
+ {
+ /* Submit the buffer to the host. */
+ VBoxVideoCmnPortWriteUlong(pCtx->port, offBuffer);
+ /* Make the compiler aware that the host has changed memory. */
+ ASMCompilerBarrier();
+ return VINF_SUCCESS;
+ }
+
+ return VERR_INVALID_PARAMETER;
+}
+
+
+/** Inform the host of the location of the host flags in VRAM via an HGSMI
+ * command. */
+static int vboxHGSMIReportFlagsLocation(PHGSMIGUESTCOMMANDCONTEXT pCtx,
+ HGSMIOFFSET offLocation)
+{
+ HGSMIBUFFERLOCATION *p;
+ int rc = VINF_SUCCESS;
+
+ /* Allocate the IO buffer. */
+ p = (HGSMIBUFFERLOCATION *)VBoxHGSMIBufferAlloc(pCtx,
+ sizeof(HGSMIBUFFERLOCATION),
+ HGSMI_CH_HGSMI,
+ HGSMI_CC_HOST_FLAGS_LOCATION);
+ if (p)
+ {
+ /* Prepare data to be sent to the host. */
+ p->offLocation = offLocation;
+ p->cbLocation = sizeof(HGSMIHOSTFLAGS);
+ rc = VBoxHGSMIBufferSubmit(pCtx, p);
+ /* Free the IO buffer. */
+ VBoxHGSMIBufferFree(pCtx, p);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ return rc;
+}
+
+
+/**
+ * Inform the host of the location of the host flags in VRAM via an HGSMI
+ * command.
+ * @returns IPRT status value.
+ * @returns VERR_NOT_IMPLEMENTED if the host does not support the command.
+ * @returns VERR_NO_MEMORY if a heap allocation fails.
+ * @param pCtx the context of the guest heap to use.
+ * @param offLocation the offset chosen for the flags withing guest
+ * VRAM.
+ */
+DECLHIDDEN(int) VBoxHGSMIReportFlagsLocation(PHGSMIGUESTCOMMANDCONTEXT pCtx,
+ HGSMIOFFSET offLocation)
+{
+ return vboxHGSMIReportFlagsLocation(pCtx, offLocation);
+}
+
+
+/** Notify the host of HGSMI-related guest capabilities via an HGSMI command.
+ */
+static int vboxHGSMISendCapsInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx,
+ uint32_t fCaps)
+{
+ VBVACAPS *pCaps;
+ int rc = VINF_SUCCESS;
+
+ /* Allocate the IO buffer. */
+ pCaps = (VBVACAPS *)VBoxHGSMIBufferAlloc(pCtx,
+ sizeof(VBVACAPS), HGSMI_CH_VBVA,
+ VBVA_INFO_CAPS);
+
+ if (pCaps)
+ {
+ /* Prepare data to be sent to the host. */
+ pCaps->rc = VERR_NOT_IMPLEMENTED;
+ pCaps->fCaps = fCaps;
+ rc = VBoxHGSMIBufferSubmit(pCtx, pCaps);
+ if (RT_SUCCESS(rc))
+ {
+ AssertRC(pCaps->rc);
+ rc = pCaps->rc;
+ }
+ /* Free the IO buffer. */
+ VBoxHGSMIBufferFree(pCtx, pCaps);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ return rc;
+}
+
+
+/**
+ * Notify the host of HGSMI-related guest capabilities via an HGSMI command.
+ * @returns IPRT status value.
+ * @returns VERR_NOT_IMPLEMENTED if the host does not support the command.
+ * @returns VERR_NO_MEMORY if a heap allocation fails.
+ * @param pCtx the context of the guest heap to use.
+ * @param fCaps the capabilities to report, see VBVACAPS.
+ */
+DECLHIDDEN(int) VBoxHGSMISendCapsInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx,
+ uint32_t fCaps)
+{
+ return vboxHGSMISendCapsInfo(pCtx, fCaps);
+}
+
+
+/** Tell the host about the location of the area of VRAM set aside for the host
+ * heap. */
+static int vboxHGSMIReportHostArea(PHGSMIGUESTCOMMANDCONTEXT pCtx,
+ uint32_t u32AreaOffset, uint32_t u32AreaSize)
+{
+ VBVAINFOHEAP *p;
+ int rc = VINF_SUCCESS;
+
+ /* Allocate the IO buffer. */
+ p = (VBVAINFOHEAP *)VBoxHGSMIBufferAlloc(pCtx,
+ sizeof (VBVAINFOHEAP), HGSMI_CH_VBVA,
+ VBVA_INFO_HEAP);
+ if (p)
+ {
+ /* Prepare data to be sent to the host. */
+ p->u32HeapOffset = u32AreaOffset;
+ p->u32HeapSize = u32AreaSize;
+ rc = VBoxHGSMIBufferSubmit(pCtx, p);
+ /* Free the IO buffer. */
+ VBoxHGSMIBufferFree(pCtx, p);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ return rc;
+}
+
+
+/**
+ * Get the information needed to map the basic communication structures in
+ * device memory into our address space. All pointer parameters are optional.
+ *
+ * @param cbVRAM how much video RAM is allocated to the device
+ * @param poffVRAMBaseMapping where to save the offset from the start of the
+ * device VRAM of the whole area to map
+ * @param pcbMapping where to save the mapping size
+ * @param poffGuestHeapMemory where to save the offset into the mapped area
+ * of the guest heap backing memory
+ * @param pcbGuestHeapMemory where to save the size of the guest heap
+ * backing memory
+ * @param poffHostFlags where to save the offset into the mapped area
+ * of the host flags
+ */
+DECLHIDDEN(void) VBoxHGSMIGetBaseMappingInfo(uint32_t cbVRAM,
+ uint32_t *poffVRAMBaseMapping,
+ uint32_t *pcbMapping,
+ uint32_t *poffGuestHeapMemory,
+ uint32_t *pcbGuestHeapMemory,
+ uint32_t *poffHostFlags)
+{
+ AssertPtrNullReturnVoid(poffVRAMBaseMapping);
+ AssertPtrNullReturnVoid(pcbMapping);
+ AssertPtrNullReturnVoid(poffGuestHeapMemory);
+ AssertPtrNullReturnVoid(pcbGuestHeapMemory);
+ AssertPtrNullReturnVoid(poffHostFlags);
+ if (poffVRAMBaseMapping)
+ *poffVRAMBaseMapping = cbVRAM - VBVA_ADAPTER_INFORMATION_SIZE;
+ if (pcbMapping)
+ *pcbMapping = VBVA_ADAPTER_INFORMATION_SIZE;
+ if (poffGuestHeapMemory)
+ *poffGuestHeapMemory = 0;
+ if (pcbGuestHeapMemory)
+ *pcbGuestHeapMemory = VBVA_ADAPTER_INFORMATION_SIZE
+ - sizeof(HGSMIHOSTFLAGS);
+ if (poffHostFlags)
+ *poffHostFlags = VBVA_ADAPTER_INFORMATION_SIZE
+ - sizeof(HGSMIHOSTFLAGS);
+}
+
+
+/**
+ * Set up the HGSMI guest-to-host command context.
+ * @returns iprt status value
+ * @param pCtx the context to set up
+ * @param pvGuestHeapMemory a pointer to the mapped backing memory for
+ * the guest heap
+ * @param cbGuestHeapMemory the size of the backing memory area
+ * @param offVRAMGuestHeapMemory the offset of the memory pointed to by
+ * @a pvGuestHeapMemory within the video RAM
+ */
+DECLHIDDEN(int) VBoxHGSMISetupGuestContext(PHGSMIGUESTCOMMANDCONTEXT pCtx,
+ void *pvGuestHeapMemory,
+ uint32_t cbGuestHeapMemory,
+ uint32_t offVRAMGuestHeapMemory,
+ const HGSMIENV *pEnv)
+{
+ /** @todo should we be using a fixed ISA port value here? */
+ pCtx->port = (RTIOPORT)VGA_PORT_HGSMI_GUEST;
+#ifdef VBOX_WDDM_MINIPORT
+ return VBoxSHGSMIInit(&pCtx->heapCtx, pvGuestHeapMemory,
+ cbGuestHeapMemory, offVRAMGuestHeapMemory, pEnv);
+#else
+ return HGSMIHeapSetup(&pCtx->heapCtx, pvGuestHeapMemory,
+ cbGuestHeapMemory, offVRAMGuestHeapMemory, pEnv);
+#endif
+}
+
+
+/**
+ * Get the information needed to map the area used by the host to send back
+ * requests.
+ *
+ * @param pCtx the context containing the heap to use
+ * @param cbVRAM how much video RAM is allocated to the device
+ * @param offVRAMBaseMapping the offset of the basic communication structures
+ * into the guest's VRAM
+ * @param poffVRAMHostArea where to store the offset into VRAM of the host
+ * heap area
+ * @param pcbHostArea where to store the size of the host heap area
+ */
+DECLHIDDEN(void) VBoxHGSMIGetHostAreaMapping(PHGSMIGUESTCOMMANDCONTEXT pCtx,
+ uint32_t cbVRAM,
+ uint32_t offVRAMBaseMapping,
+ uint32_t *poffVRAMHostArea,
+ uint32_t *pcbHostArea)
+{
+ uint32_t offVRAMHostArea = offVRAMBaseMapping, cbHostArea = 0;
+
+ AssertPtrReturnVoid(poffVRAMHostArea);
+ AssertPtrReturnVoid(pcbHostArea);
+ VBoxQueryConfHGSMI(pCtx, VBOX_VBVA_CONF32_HOST_HEAP_SIZE, &cbHostArea);
+ if (cbHostArea != 0)
+ {
+ uint32_t cbHostAreaMaxSize = cbVRAM / 4;
+ /** @todo what is the idea of this? */
+ if (cbHostAreaMaxSize >= VBVA_ADAPTER_INFORMATION_SIZE)
+ {
+ cbHostAreaMaxSize -= VBVA_ADAPTER_INFORMATION_SIZE;
+ }
+ if (cbHostArea > cbHostAreaMaxSize)
+ {
+ cbHostArea = cbHostAreaMaxSize;
+ }
+ /* Round up to 4096 bytes. */
+ cbHostArea = (cbHostArea + 0xFFF) & ~0xFFF;
+ offVRAMHostArea = offVRAMBaseMapping - cbHostArea;
+ }
+
+ *pcbHostArea = cbHostArea;
+ *poffVRAMHostArea = offVRAMHostArea;
+ LogFunc(("offVRAMHostArea = 0x%08X, cbHostArea = 0x%08X\n",
+ offVRAMHostArea, cbHostArea));
+}
+
+
+/**
+ * Initialise the host context structure.
+ *
+ * @param pCtx the context structure to initialise
+ * @param pvBaseMapping where the basic HGSMI structures are mapped at
+ * @param offHostFlags the offset of the host flags into the basic HGSMI
+ * structures
+ * @param pvHostAreaMapping where the area for the host heap is mapped at
+ * @param offVRAMHostArea offset of the host heap area into VRAM
+ * @param cbHostArea size in bytes of the host heap area
+ */
+DECLHIDDEN(void) VBoxHGSMISetupHostContext(PHGSMIHOSTCOMMANDCONTEXT pCtx,
+ void *pvBaseMapping,
+ uint32_t offHostFlags,
+ void *pvHostAreaMapping,
+ uint32_t offVRAMHostArea,
+ uint32_t cbHostArea)
+{
+ uint8_t *pu8HostFlags = ((uint8_t *)pvBaseMapping) + offHostFlags;
+ pCtx->pfHostFlags = (HGSMIHOSTFLAGS *)pu8HostFlags;
+ /** @todo should we really be using a fixed ISA port value here? */
+ pCtx->port = (RTIOPORT)VGA_PORT_HGSMI_HOST;
+ HGSMIAreaInitialize(&pCtx->areaCtx, pvHostAreaMapping, cbHostArea,
+ offVRAMHostArea);
+}
+
+
+/**
+ * Tell the host about the ways it can use to communicate back to us via an
+ * HGSMI command
+ *
+ * @returns iprt status value
+ * @param pCtx the context containing the heap to use
+ * @param offVRAMFlagsLocation where we wish the host to place its flags
+ * relative to the start of the VRAM
+ * @param fCaps additions HGSMI capabilities the guest
+ * supports
+ * @param offVRAMHostArea offset into VRAM of the host heap area
+ * @param cbHostArea size in bytes of the host heap area
+ */
+DECLHIDDEN(int) VBoxHGSMISendHostCtxInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx,
+ HGSMIOFFSET offVRAMFlagsLocation,
+ uint32_t fCaps,
+ uint32_t offVRAMHostArea,
+ uint32_t cbHostArea)
+{
+ Log(("VBoxVideo::vboxSetupAdapterInfo\n"));
+
+ /* setup the flags first to ensure they are initialized by the time the
+ * host heap is ready */
+ int rc = vboxHGSMIReportFlagsLocation(pCtx, offVRAMFlagsLocation);
+ AssertRC(rc);
+ if (RT_SUCCESS(rc) && fCaps)
+ {
+ /* Inform about caps */
+ rc = vboxHGSMISendCapsInfo(pCtx, fCaps);
+ AssertRC(rc);
+ }
+ if (RT_SUCCESS (rc))
+ {
+ /* Report the host heap location. */
+ rc = vboxHGSMIReportHostArea(pCtx, offVRAMHostArea, cbHostArea);
+ AssertRC(rc);
+ }
+ Log(("VBoxVideo::vboxSetupAdapterInfo finished rc = %d\n", rc));
+ return rc;
+}
+
+
+/** Sanity test on first call. We do not worry about concurrency issues. */
+static int testQueryConf(PHGSMIGUESTCOMMANDCONTEXT pCtx)
+{
+ static bool cOnce = false;
+ uint32_t ulValue = 0;
+ int rc;
+
+ if (cOnce)
+ return VINF_SUCCESS;
+ cOnce = true;
+ rc = VBoxQueryConfHGSMI(pCtx, UINT32_MAX, &ulValue);
+ if (RT_SUCCESS(rc) && ulValue == UINT32_MAX)
+ return VINF_SUCCESS;
+ cOnce = false;
+ if (RT_FAILURE(rc))
+ return rc;
+ return VERR_INTERNAL_ERROR;
+}
+
+
+/**
+ * Query the host for an HGSMI configuration parameter via an HGSMI command.
+ * @returns iprt status value
+ * @param pCtx the context containing the heap used
+ * @param u32Index the index of the parameter to query,
+ * @see VBVACONF32::u32Index
+ * @param u32DefValue defaut value
+ * @param pulValue where to store the value of the parameter on success
+ */
+DECLHIDDEN(int) VBoxQueryConfHGSMIDef(PHGSMIGUESTCOMMANDCONTEXT pCtx,
+ uint32_t u32Index, uint32_t u32DefValue, uint32_t *pulValue)
+{
+ int rc = VINF_SUCCESS;
+ VBVACONF32 *p;
+ LogFunc(("u32Index = %d\n", u32Index));
+
+ rc = testQueryConf(pCtx);
+ if (RT_FAILURE(rc))
+ return rc;
+ /* Allocate the IO buffer. */
+ p = (VBVACONF32 *)VBoxHGSMIBufferAlloc(pCtx,
+ sizeof(VBVACONF32), HGSMI_CH_VBVA,
+ VBVA_QUERY_CONF32);
+ if (p)
+ {
+ /* Prepare data to be sent to the host. */
+ p->u32Index = u32Index;
+ p->u32Value = u32DefValue;
+ rc = VBoxHGSMIBufferSubmit(pCtx, p);
+ if (RT_SUCCESS(rc))
+ {
+ *pulValue = p->u32Value;
+ LogFunc(("u32Value = %d\n", p->u32Value));
+ }
+ /* Free the IO buffer. */
+ VBoxHGSMIBufferFree(pCtx, p);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ LogFunc(("rc = %d\n", rc));
+ return rc;
+}
+
+DECLHIDDEN(int) VBoxQueryConfHGSMI(PHGSMIGUESTCOMMANDCONTEXT pCtx,
+ uint32_t u32Index, uint32_t *pulValue)
+{
+ return VBoxQueryConfHGSMIDef(pCtx, u32Index, UINT32_MAX, pulValue);
+}
+
+/**
+ * Pass the host a new mouse pointer shape via an HGSMI command.
+ *
+ * @returns success or failure
+ * @param fFlags cursor flags, @see VMMDevReqMousePointer::fFlags
+ * @param cHotX horizontal position of the hot spot
+ * @param cHotY vertical position of the hot spot
+ * @param cWidth width in pixels of the cursor
+ * @param cHeight height in pixels of the cursor
+ * @param pPixels pixel data, @see VMMDevReqMousePointer for the format
+ * @param cbLength size in bytes of the pixel data
+ */
+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)
+{
+ VBVAMOUSEPOINTERSHAPE *p;
+ uint32_t cbData = 0;
+ int rc = VINF_SUCCESS;
+
+ if (fFlags & VBOX_MOUSE_POINTER_SHAPE)
+ {
+ /* Size of the pointer data: sizeof (AND mask) + sizeof (XOR_MASK) */
+ cbData = ((((cWidth + 7) / 8) * cHeight + 3) & ~3)
+ + cWidth * 4 * cHeight;
+ /* If shape is supplied, then always create the pointer visible.
+ * See comments in 'vboxUpdatePointerShape'
+ */
+ fFlags |= VBOX_MOUSE_POINTER_VISIBLE;
+ }
+ LogFlowFunc(("cbData %d, %dx%d\n", cbData, cWidth, cHeight));
+ if (cbData > cbLength)
+ {
+ LogFunc(("calculated pointer data size is too big (%d bytes, limit %d)\n",
+ cbData, cbLength));
+ return VERR_INVALID_PARAMETER;
+ }
+ /* Allocate the IO buffer. */
+ p = (VBVAMOUSEPOINTERSHAPE *)VBoxHGSMIBufferAlloc(pCtx,
+ sizeof(VBVAMOUSEPOINTERSHAPE)
+ + cbData,
+ HGSMI_CH_VBVA,
+ VBVA_MOUSE_POINTER_SHAPE);
+ if (p)
+ {
+ /* Prepare data to be sent to the host. */
+ /* Will be updated by the host. */
+ p->i32Result = VINF_SUCCESS;
+ /* We have our custom flags in the field */
+ p->fu32Flags = fFlags;
+ p->u32HotX = cHotX;
+ p->u32HotY = cHotY;
+ p->u32Width = cWidth;
+ p->u32Height = cHeight;
+ if (p->fu32Flags & VBOX_MOUSE_POINTER_SHAPE)
+ /* Copy the actual pointer data. */
+ memcpy (p->au8Data, pPixels, cbData);
+ rc = VBoxHGSMIBufferSubmit(pCtx, p);
+ if (RT_SUCCESS(rc))
+ rc = p->i32Result;
+ /* Free the IO buffer. */
+ VBoxHGSMIBufferFree(pCtx, p);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ LogFlowFunc(("rc %d\n", rc));
+ return rc;
+}
+
+
+/**
+ * Report the guest cursor position. The host may wish to use this information
+ * to re-position its own cursor (though this is currently unlikely). The
+ * current host cursor position is returned.
+ * @param pCtx The context containing the heap used.
+ * @param fReportPosition Are we reporting a position?
+ * @param x Guest cursor X position.
+ * @param y Guest cursor Y position.
+ * @param pxHost Host cursor X position is stored here. Optional.
+ * @param pyHost Host cursor Y position is stored here. Optional.
+ * @returns iprt status code.
+ * @returns VERR_NO_MEMORY HGSMI heap allocation failed.
+ */
+DECLHIDDEN(int) VBoxHGSMICursorPosition(PHGSMIGUESTCOMMANDCONTEXT pCtx, bool fReportPosition, uint32_t x, uint32_t y,
+ uint32_t *pxHost, uint32_t *pyHost)
+{
+ int rc = VINF_SUCCESS;
+ VBVACURSORPOSITION *p;
+ Log(("%s: x=%u, y=%u\n", __PRETTY_FUNCTION__, (unsigned)x, (unsigned)y));
+
+ /* Allocate the IO buffer. */
+ p = (VBVACURSORPOSITION *)VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVACURSORPOSITION), HGSMI_CH_VBVA, VBVA_CURSOR_POSITION);
+ if (p)
+ {
+ /* Prepare data to be sent to the host. */
+ p->fReportPosition = fReportPosition ? 1 : 0;
+ p->x = x;
+ p->y = y;
+ rc = VBoxHGSMIBufferSubmit(pCtx, p);
+ if (RT_SUCCESS(rc))
+ {
+ if (pxHost)
+ *pxHost = p->x;
+ if (pyHost)
+ *pyHost = p->y;
+ Log(("%s: return: x=%u, y=%u\n", __PRETTY_FUNCTION__, (unsigned)p->x, (unsigned)p->y));
+ }
+ /* Free the IO buffer. */
+ VBoxHGSMIBufferFree(pCtx, p);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ LogFunc(("rc = %d\n", rc));
+ return rc;
+}
+
+
+/** @todo Mouse pointer position to be read from VMMDev memory, address of the memory region
+ * can be queried from VMMDev via an IOCTL. This VMMDev memory region will contain
+ * host information which is needed by the guest.
+ *
+ * Reading will not cause a switch to the host.
+ *
+ * Have to take into account:
+ * * synchronization: host must write to the memory only from EMT,
+ * large structures must be read under flag, which tells the host
+ * that the guest is currently reading the memory (OWNER flag?).
+ * * guest writes: may be allocate a page for the host info and make
+ * the page readonly for the guest.
+ * * the information should be available only for additions drivers.
+ * * VMMDev additions driver will inform the host which version of the info it expects,
+ * host must support all versions.
+ *
+ */
--- /dev/null
+/* $Id: HGSMICommon.cpp $ */
+/** @file
+ * VBox Host Guest Shared Memory Interface (HGSMI) - Functions common to both host and guest.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#define LOG_DISABLED /* Maybe we can enabled it all the time now? */
+#define LOG_GROUP LOG_GROUP_HGSMI
+#include <iprt/heap.h>
+#include <iprt/string.h>
+
+#include <VBox/HGSMI/HGSMI.h>
+#include <VBox/log.h>
+
+
+/* Channel flags. */
+#define HGSMI_CH_F_REGISTERED 0x01
+
+/* Assertions for situations which could happen and normally must be processed properly
+ * but must be investigated during development: guest misbehaving, etc.
+ */
+#ifdef HGSMI_STRICT
+#define HGSMI_STRICT_ASSERT_FAILED() AssertFailed()
+#define HGSMI_STRICT_ASSERT(expr) Assert(expr)
+#else
+#define HGSMI_STRICT_ASSERT_FAILED() do {} while (0)
+#define HGSMI_STRICT_ASSERT(expr) do {} while (0)
+#endif /* !HGSMI_STRICT */
+
+/* One-at-a-Time Hash from
+ * http://www.burtleburtle.net/bob/hash/doobs.html
+ *
+ * ub4 one_at_a_time(char *key, ub4 len)
+ * {
+ * ub4 hash, i;
+ * for (hash=0, i=0; i<len; ++i)
+ * {
+ * hash += key[i];
+ * hash += (hash << 10);
+ * hash ^= (hash >> 6);
+ * }
+ * hash += (hash << 3);
+ * hash ^= (hash >> 11);
+ * hash += (hash << 15);
+ * return hash;
+ * }
+ */
+
+static uint32_t hgsmiHashBegin(void)
+{
+ return 0;
+}
+
+static uint32_t hgsmiHashProcess(uint32_t hash,
+ const void *pvData,
+ size_t cbData)
+{
+ const uint8_t *pu8Data = (const uint8_t *)pvData;
+
+ while (cbData--)
+ {
+ hash += *pu8Data++;
+ hash += (hash << 10);
+ hash ^= (hash >> 6);
+ }
+
+ return hash;
+}
+
+static uint32_t hgsmiHashEnd(uint32_t hash)
+{
+ hash += (hash << 3);
+ hash ^= (hash >> 11);
+ hash += (hash << 15);
+
+ return hash;
+}
+
+uint32_t HGSMIChecksum(HGSMIOFFSET offBuffer,
+ const HGSMIBUFFERHEADER *pHeader,
+ const HGSMIBUFFERTAIL *pTail)
+{
+ uint32_t u32Checksum = hgsmiHashBegin();
+
+ u32Checksum = hgsmiHashProcess(u32Checksum, &offBuffer, sizeof(offBuffer));
+ u32Checksum = hgsmiHashProcess(u32Checksum, pHeader, sizeof(HGSMIBUFFERHEADER));
+ u32Checksum = hgsmiHashProcess(u32Checksum, pTail, RT_OFFSETOF(HGSMIBUFFERTAIL, u32Checksum));
+
+ return hgsmiHashEnd(u32Checksum);
+}
+
+int HGSMIAreaInitialize(HGSMIAREA *pArea,
+ void *pvBase,
+ HGSMISIZE cbArea,
+ HGSMIOFFSET offBase)
+{
+ uint8_t *pu8Base = (uint8_t *)pvBase;
+
+ if ( !pArea /* Check that the area: */
+ || cbArea < HGSMIBufferMinimumSize() /* large enough; */
+ || pu8Base + cbArea < pu8Base /* no address space wrap; */
+ || offBase > UINT32_C(0xFFFFFFFF) - cbArea /* area within the 32 bit space: offBase + cbMem <= 0xFFFFFFFF. */
+ )
+ {
+ return VERR_INVALID_PARAMETER;
+ }
+
+ pArea->pu8Base = pu8Base;
+ pArea->offBase = offBase;
+ pArea->offLast = cbArea - HGSMIBufferMinimumSize() + offBase;
+ pArea->cbArea = cbArea;
+
+ return VINF_SUCCESS;
+}
+
+void HGSMIAreaClear(HGSMIAREA *pArea)
+{
+ if (pArea)
+ {
+ RT_ZERO(*pArea);
+ }
+}
+
+/* Initialize the memory buffer including its checksum.
+ * No changes alloed to the header and the tail after that.
+ */
+HGSMIOFFSET HGSMIBufferInitializeSingle(const HGSMIAREA *pArea,
+ HGSMIBUFFERHEADER *pHeader,
+ HGSMISIZE cbBuffer,
+ uint8_t u8Channel,
+ uint16_t u16ChannelInfo)
+{
+ if ( !pArea
+ || !pHeader
+ || cbBuffer < HGSMIBufferMinimumSize())
+ {
+ return HGSMIOFFSET_VOID;
+ }
+
+ /* Buffer must be within the area:
+ * * header data size do not exceed the maximum data size;
+ * * buffer address is greater than the area base address;
+ * * buffer address is lower than the maximum allowed for the given data size.
+ */
+ HGSMISIZE cbMaximumDataSize = pArea->offLast - pArea->offBase;
+ uint32_t u32DataSize = cbBuffer - HGSMIBufferMinimumSize();
+
+ if ( u32DataSize > cbMaximumDataSize
+ || (uint8_t *)pHeader < pArea->pu8Base
+ || (uint8_t *)pHeader > pArea->pu8Base + cbMaximumDataSize - u32DataSize)
+ {
+ return HGSMIOFFSET_VOID;
+ }
+
+ HGSMIOFFSET offBuffer = HGSMIPointerToOffset(pArea, pHeader);
+
+ pHeader->u8Flags = HGSMI_BUFFER_HEADER_F_SEQ_SINGLE;
+ pHeader->u32DataSize = u32DataSize;
+ pHeader->u8Channel = u8Channel;
+ pHeader->u16ChannelInfo = u16ChannelInfo;
+ RT_ZERO(pHeader->u.au8Union);
+
+ HGSMIBUFFERTAIL *pTail = HGSMIBufferTailFromPtr(pHeader, u32DataSize);
+ pTail->u32Reserved = 0;
+ pTail->u32Checksum = HGSMIChecksum(offBuffer, pHeader, pTail);
+
+ return offBuffer;
+}
+
+int HGSMIHeapSetup(HGSMIHEAP *pHeap,
+ void *pvBase,
+ HGSMISIZE cbArea,
+ HGSMIOFFSET offBase,
+ const HGSMIENV *pEnv)
+{
+ AssertPtrReturn(pHeap, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pvBase, VERR_INVALID_PARAMETER);
+
+ int rc = HGSMIAreaInitialize(&pHeap->area, pvBase, cbArea, offBase);
+ if (RT_SUCCESS(rc))
+ {
+ rc = HGSMIMAInit(&pHeap->ma, &pHeap->area, NULL, 0, 0, pEnv);
+ if (RT_FAILURE(rc))
+ {
+ HGSMIAreaClear(&pHeap->area);
+ }
+ }
+
+ return rc;
+}
+
+void HGSMIHeapDestroy(HGSMIHEAP *pHeap)
+{
+ if (pHeap)
+ {
+ HGSMIMAUninit(&pHeap->ma);
+ RT_ZERO(*pHeap);
+ }
+}
+
+void *HGSMIHeapAlloc(HGSMIHEAP *pHeap,
+ HGSMISIZE cbData,
+ uint8_t u8Channel,
+ uint16_t u16ChannelInfo)
+{
+ HGSMISIZE cbAlloc = HGSMIBufferRequiredSize(cbData);
+ HGSMIBUFFERHEADER *pHeader = (HGSMIBUFFERHEADER *)HGSMIHeapBufferAlloc(pHeap, cbAlloc);
+ if (pHeader)
+ {
+ HGSMIOFFSET offBuffer = HGSMIBufferInitializeSingle(HGSMIHeapArea(pHeap), pHeader,
+ cbAlloc, u8Channel, u16ChannelInfo);
+ if (offBuffer == HGSMIOFFSET_VOID)
+ {
+ HGSMIHeapBufferFree(pHeap, pHeader);
+ pHeader = NULL;
+ }
+ }
+
+ return pHeader? HGSMIBufferDataFromPtr(pHeader): NULL;
+}
+
+void HGSMIHeapFree(HGSMIHEAP *pHeap,
+ void *pvData)
+{
+ if (pvData)
+ {
+ HGSMIBUFFERHEADER *pHeader = HGSMIBufferHeaderFromData(pvData);
+ HGSMIHeapBufferFree(pHeap, pHeader);
+ }
+}
+
+void *HGSMIHeapBufferAlloc(HGSMIHEAP *pHeap,
+ HGSMISIZE cbBuffer)
+{
+ void *pvBuf = HGSMIMAAlloc(&pHeap->ma, cbBuffer);
+ return pvBuf;
+}
+
+void HGSMIHeapBufferFree(HGSMIHEAP *pHeap,
+ void *pvBuf)
+{
+ HGSMIMAFree(&pHeap->ma, pvBuf);
+}
+
+typedef struct HGSMIBUFFERCONTEXT
+{
+ const HGSMIBUFFERHEADER *pHeader; /* The original buffer header. */
+ void *pvData; /* Payload data in the buffer./ */
+ uint32_t cbData; /* Size of data */
+} HGSMIBUFFERCONTEXT;
+
+/** Verify that the given offBuffer points to a valid buffer, which is within the area.
+ *
+ * @returns VBox status and the buffer information in pBufferContext.
+ * @param pArea Area which supposed to contain the buffer.
+ * @param offBuffer The buffer location in the area.
+ * @param pBufferContext Where to write information about the buffer.
+ */
+static int hgsmiVerifyBuffer(const HGSMIAREA *pArea,
+ HGSMIOFFSET offBuffer,
+ HGSMIBUFFERCONTEXT *pBufferContext)
+{
+ LogFlowFunc(("buffer 0x%x, area %p %x [0x%x;0x%x]\n",
+ offBuffer, pArea->pu8Base, pArea->cbArea, pArea->offBase, pArea->offLast));
+
+ int rc = VINF_SUCCESS;
+
+ if ( offBuffer < pArea->offBase
+ || offBuffer > pArea->offLast)
+ {
+ LogFunc(("offset 0x%x is outside the area [0x%x;0x%x]!!!\n",
+ offBuffer, pArea->offBase, pArea->offLast));
+ rc = VERR_INVALID_PARAMETER;
+ HGSMI_STRICT_ASSERT_FAILED();
+ }
+ else
+ {
+ void *pvBuffer = HGSMIOffsetToPointer(pArea, offBuffer);
+ HGSMIBUFFERHEADER header = *HGSMIBufferHeaderFromPtr(pvBuffer);
+
+ /* Quick check of the data size, it should be less than the maximum
+ * data size for the buffer at this offset.
+ */
+ LogFlowFunc(("datasize check: header.u32DataSize = 0x%x pArea->offLast - offBuffer = 0x%x\n",
+ header.u32DataSize, pArea->offLast - offBuffer));
+
+ if (header.u32DataSize <= pArea->offLast - offBuffer)
+ {
+ HGSMIBUFFERTAIL tail = *HGSMIBufferTailFromPtr(pvBuffer, header.u32DataSize);
+
+ /* At least both header and tail structures are in the area. Check the checksum. */
+ uint32_t u32Checksum = HGSMIChecksum(offBuffer, &header, &tail);
+ LogFlowFunc(("checksum check: u32Checksum = 0x%x pTail->u32Checksum = 0x%x\n",
+ u32Checksum, tail.u32Checksum));
+ if (u32Checksum == tail.u32Checksum)
+ {
+ /* Success. */
+ pBufferContext->pHeader = HGSMIBufferHeaderFromPtr(pvBuffer);
+ pBufferContext->pvData = HGSMIBufferDataFromPtr(pvBuffer);
+ pBufferContext->cbData = header.u32DataSize;
+ }
+ else
+ {
+ LogFunc(("invalid checksum 0x%x, expected 0x%x!!!\n",
+ u32Checksum, tail.u32Checksum));
+ rc = VERR_INVALID_STATE;
+ HGSMI_STRICT_ASSERT_FAILED();
+ }
+ }
+ else
+ {
+ LogFunc(("invalid data size 0x%x, maximum is 0x%x!!!\n",
+ header.u32DataSize, pArea->offLast - offBuffer));
+ rc = VERR_TOO_MUCH_DATA;
+ HGSMI_STRICT_ASSERT_FAILED();
+ }
+ }
+
+ return rc;
+}
+
+/** Helper to convert HGSMI channel index to the channel structure pointer.
+ *
+ * @returns Pointer to the channel data.
+ * @param pChannelInfo The channel pool.
+ * @param u8Channel The channel index.
+ */
+HGSMICHANNEL *HGSMIChannelFindById(HGSMICHANNELINFO *pChannelInfo,
+ uint8_t u8Channel)
+{
+ AssertCompile(RT_ELEMENTS(pChannelInfo->Channels) >= 0x100);
+ HGSMICHANNEL *pChannel = &pChannelInfo->Channels[u8Channel];
+
+ if (pChannel->u8Flags & HGSMI_CH_F_REGISTERED)
+ {
+ return pChannel;
+ }
+
+ return NULL;
+}
+
+/** Process a guest buffer.
+ *
+ * @returns VBox status code.
+ * @param pArea Area which supposed to contain the buffer.
+ * @param pChannelInfo The channel pool.
+ * @param offBuffer The buffer location in the area.
+ */
+int HGSMIBufferProcess(const HGSMIAREA *pArea,
+ HGSMICHANNELINFO *pChannelInfo,
+ HGSMIOFFSET offBuffer)
+{
+ LogFlowFunc(("pArea %p, offBuffer 0x%x\n", pArea, offBuffer));
+
+ AssertPtrReturn(pArea, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pChannelInfo, VERR_INVALID_PARAMETER);
+
+ /* Guest has prepared a command description at 'offBuffer'. */
+ HGSMIBUFFERCONTEXT bufferContext = { NULL, NULL, 0 }; /* Makes old GCC happier. */
+ int rc = hgsmiVerifyBuffer(pArea, offBuffer, &bufferContext);
+ if (RT_SUCCESS(rc))
+ {
+ /* Pass the command to the appropriate handler registered with this instance.
+ * Start with the handler list head, which is the preallocated HGSMI setup channel.
+ */
+ const HGSMICHANNEL *pChannel = HGSMIChannelFindById(pChannelInfo, bufferContext.pHeader->u8Channel);
+ if (pChannel)
+ {
+ const HGSMICHANNELHANDLER *pHandler = &pChannel->handler;
+ if (pHandler->pfnHandler)
+ {
+ pHandler->pfnHandler(pHandler->pvHandler, bufferContext.pHeader->u16ChannelInfo,
+ bufferContext.pvData, bufferContext.cbData);
+ }
+ HGSMI_STRICT_ASSERT(RT_SUCCESS(hgsmiVerifyBuffer(pArea, offBuffer, &bufferContext)));
+ }
+ else
+ {
+ rc = VERR_INVALID_FUNCTION;
+ HGSMI_STRICT_ASSERT_FAILED();
+ }
+ }
+
+ return rc;
+}
+
+/** Register a new HGSMI channel by index.
+ *
+ * @returns VBox status code.
+ * @param pChannelInfo The channel pool managed by the caller.
+ * @param u8Channel Index of the channel.
+ * @param pszName Name of the channel (optional, allocated by the caller).
+ * @param pfnChannelHandler The channel callback.
+ * @param pvChannelHandler The callback pointer.
+ */
+int HGSMIChannelRegister(HGSMICHANNELINFO *pChannelInfo,
+ uint8_t u8Channel,
+ const char *pszName,
+ PFNHGSMICHANNELHANDLER pfnChannelHandler,
+ void *pvChannelHandler)
+{
+ /* Check whether the channel is already registered. */
+ HGSMICHANNEL *pChannel = HGSMIChannelFindById(pChannelInfo, u8Channel);
+ if (pChannel)
+ {
+ HGSMI_STRICT_ASSERT_FAILED();
+ return VERR_ALREADY_EXISTS;
+ }
+
+ /* Channel is not yet registered. */
+ pChannel = &pChannelInfo->Channels[u8Channel];
+
+ pChannel->u8Flags = HGSMI_CH_F_REGISTERED;
+ pChannel->u8Channel = u8Channel;
+
+ pChannel->handler.pfnHandler = pfnChannelHandler;
+ pChannel->handler.pvHandler = pvChannelHandler;
+
+ pChannel->pszName = pszName;
+
+ return VINF_SUCCESS;
+}
--- /dev/null
+/* $Id: HGSMIMemAlloc.cpp $ */
+/** @file
+ * VBox Host Guest Shared Memory Interface (HGSMI) - Memory allocator.
+ */
+
+/*
+ * Copyright (C) 2014-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*
+ * Memory allocator
+ * ----------------
+ *
+ * Area [0; AreaSize) contains only the data, control structures are separate.
+ * Block sizes are power of 2: 32B, ..., 1MB
+ * Area size can be anything and will be divided initially to largest possible free blocks.
+ *
+ * The entire area is described by a list of 32 bit block descriptors:
+ * * bits 0..3 - order, which is log2 size of the block - 5: 2^(0+5) ... 2^(15+5) == 32B .. 1MB
+ * * bit 4 - 1 for free blocks.
+ * * bits 5..31 - block offset.
+ *
+ * 31 ... 5 | 4 | 3 ... 0
+ * offset F order
+ *
+ * There is a sorted collection of all block descriptors
+ * (key is the block offset, bits 0...4 do not interfere with sorting).
+ * Also there are lists of free blocks for each size for fast allocation.
+ *
+ *
+ * Implementation
+ * --------------
+ *
+ * The blocks collection is a sorted linear list.
+ *
+ * Initially the entire area consists of one or more largest blocks followed by smaller blocks:
+ * * 100B area - 64B block with descriptor: 0x00000011
+ * 32B block with descriptor: 0x00000030
+ * 4B unused
+ * * 64K area - one 64K block with descriptor: 0x0000001C
+ * * 512K area - one 512K block with descriptor: 0x0000001F
+ *
+ * When allocating a new block:
+ * * larger free blocks are splitted when there are no smaller free blocks;
+ * * smaller free blocks are merged if they can build a requested larger block.
+ */
+#include <VBox/HGSMI/HGSMIMemAlloc.h>
+#include <VBox/HGSMI/HGSMI.h>
+
+#include <iprt/err.h>
+#include <iprt/string.h>
+
+
+DECLINLINE(HGSMIOFFSET) hgsmiMADescriptor(HGSMIOFFSET off, bool fFree, HGSMIOFFSET order)
+{
+ return (off & HGSMI_MA_DESC_OFFSET_MASK) |
+ (fFree? HGSMI_MA_DESC_FREE_MASK: 0) |
+ (order & HGSMI_MA_DESC_ORDER_MASK);
+}
+
+static void hgsmiMABlockFree(HGSMIMADATA *pMA, HGSMIMABLOCK *pBlock)
+{
+ pMA->env.pfnFree(pMA->env.pvEnv, pBlock);
+}
+
+static int hgsmiMABlockAlloc(HGSMIMADATA *pMA, HGSMIMABLOCK **ppBlock)
+{
+ int rc = VINF_SUCCESS;
+
+ HGSMIMABLOCK *pBlock = (HGSMIMABLOCK *)pMA->env.pfnAlloc(pMA->env.pvEnv, sizeof(HGSMIMABLOCK));
+ if (pBlock)
+ {
+ RT_ZERO(pBlock->nodeBlock);
+ *ppBlock = pBlock;
+ }
+ else
+ {
+ rc = VERR_NO_MEMORY;
+ }
+
+ return rc;
+}
+
+/* Divide entire area to free blocks. */
+static int hgsmiMAFormat(HGSMIMADATA *pMA)
+{
+ int rc = VINF_SUCCESS;
+
+ /* Initial value, it will be updated in the loop below. */
+ pMA->cbMaxBlock = HGSMI_MA_BLOCK_SIZE_MIN;
+ pMA->cBlocks = 0;
+
+ HGSMISIZE cbBlock = HGSMI_MA_BLOCK_SIZE_MAX;
+ HGSMISIZE cbRemaining = pMA->area.cbArea;
+ HGSMIOFFSET off = 0;
+
+ while (cbBlock >= HGSMI_MA_BLOCK_SIZE_MIN)
+ {
+ /* Build a list of free memory blocks with u32BlockSize. */
+ uint32_t cBlocks = cbRemaining / cbBlock;
+ if (cBlocks > 0)
+ {
+ if (pMA->cbMaxBlock < cbBlock)
+ {
+ pMA->cbMaxBlock = cbBlock;
+ }
+
+ HGSMIOFFSET order = HGSMIMASize2Order(cbBlock);
+
+ uint32_t i;
+ for (i = 0; i < cBlocks; ++i)
+ {
+ /* A new free block. */
+ HGSMIMABLOCK *pBlock;
+ rc = hgsmiMABlockAlloc(pMA, &pBlock);
+ if (RT_FAILURE(rc))
+ {
+ break;
+ }
+
+ pBlock->descriptor = hgsmiMADescriptor(off, true, order);
+ RTListAppend(&pMA->listBlocks, &pBlock->nodeBlock);
+ ++pMA->cBlocks;
+
+ off += cbBlock;
+ cbRemaining -= cbBlock;
+ }
+ }
+
+ if (RT_FAILURE(rc))
+ {
+ break;
+ }
+
+ cbBlock /= 2;
+ }
+
+ return rc;
+}
+
+static int hgsmiMARebuildFreeLists(HGSMIMADATA *pMA)
+{
+ int rc = VINF_SUCCESS;
+
+ HGSMIMABLOCK *pIter;
+ RTListForEach(&pMA->listBlocks, pIter, HGSMIMABLOCK, nodeBlock)
+ {
+ if (HGSMI_MA_DESC_IS_FREE(pIter->descriptor))
+ {
+ HGSMIOFFSET order = HGSMI_MA_DESC_ORDER(pIter->descriptor);
+ RTListAppend(&pMA->aListFreeBlocks[order], &pIter->nodeFree);
+ }
+ }
+
+ return rc;
+}
+
+static int hgsmiMARestore(HGSMIMADATA *pMA, HGSMIOFFSET *paDescriptors, uint32_t cDescriptors, HGSMISIZE cbMaxBlock)
+{
+ int rc = VINF_SUCCESS;
+
+ pMA->cbMaxBlock = cbMaxBlock;
+ pMA->cBlocks = 0;
+
+ HGSMISIZE cbRemaining = pMA->area.cbArea;
+ HGSMIOFFSET off = 0;
+
+ uint32_t i;
+ for (i = 0; i < cDescriptors; ++i)
+ {
+ /* Verify the descriptor. */
+ HGSMISIZE cbBlock = HGSMIMAOrder2Size(HGSMI_MA_DESC_ORDER(paDescriptors[i]));
+ if ( off != HGSMI_MA_DESC_OFFSET(paDescriptors[i])
+ || cbBlock > cbRemaining
+ || cbBlock > pMA->cbMaxBlock)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ /* A new free block. */
+ HGSMIMABLOCK *pBlock;
+ rc = hgsmiMABlockAlloc(pMA, &pBlock);
+ if (RT_FAILURE(rc))
+ {
+ break;
+ }
+
+ pBlock->descriptor = paDescriptors[i];
+ RTListAppend(&pMA->listBlocks, &pBlock->nodeBlock);
+ ++pMA->cBlocks;
+
+ off += cbBlock;
+ cbRemaining -= cbBlock;
+ }
+
+ return rc;
+}
+
+static HGSMIMABLOCK *hgsmiMAGetFreeBlock(HGSMIMADATA *pMA, HGSMIOFFSET order)
+{
+ HGSMIMABLOCK *pBlock = NULL;
+
+ HGSMIOFFSET i;
+ for (i = order; i < RT_ELEMENTS(pMA->aListFreeBlocks); ++i)
+ {
+ pBlock = RTListGetFirst(&pMA->aListFreeBlocks[i], HGSMIMABLOCK, nodeFree);
+ if (pBlock)
+ {
+ break;
+ }
+ }
+
+ if (pBlock)
+ {
+ AssertReturn(HGSMI_MA_DESC_IS_FREE(pBlock->descriptor), NULL);
+
+ /* Where the block starts. */
+ HGSMIOFFSET off = HGSMI_MA_DESC_OFFSET(pBlock->descriptor);
+
+ /* 'i' is the order of the block. */
+ while (i != order)
+ {
+ /* A larger block was found and need to be split to 2 smaller blocks. */
+ HGSMIMABLOCK *pBlock2;
+ int rc = hgsmiMABlockAlloc(pMA, &pBlock2);
+ if (RT_FAILURE(rc))
+ {
+ pBlock = NULL;
+ break;
+ }
+
+ /* Create 2 blocks with descreased order. */
+ --i;
+
+ /* Remove from the free list. */
+ RTListNodeRemove(&pBlock->nodeFree);
+
+ pBlock->descriptor = hgsmiMADescriptor(off, true, i);
+ pBlock2->descriptor = hgsmiMADescriptor(off + HGSMIMAOrder2Size(i), true, i);
+
+ /* Update list of all blocks by inserting pBlock2 after pBlock. */
+ RTListNodeInsertAfter(&pBlock->nodeBlock, &pBlock2->nodeBlock);
+ ++pMA->cBlocks;
+
+ /* Update the free list. */
+ RTListAppend(&pMA->aListFreeBlocks[i], &pBlock->nodeFree);
+ RTListAppend(&pMA->aListFreeBlocks[i], &pBlock2->nodeFree);
+ }
+ }
+
+ return pBlock;
+}
+
+static void hgsmiMAReformatFreeBlocks(HGSMIMADATA *pMA, HGSMIOFFSET maxId,
+ HGSMIMABLOCK *pStart, HGSMIMABLOCK *pEnd, HGSMISIZE cbBlocks)
+{
+ int rc = VINF_SUCCESS;
+
+ /*
+ * Blocks starting from pStart until pEnd will be replaced with
+ * another set of blocks.
+ *
+ * The new set will include the block with the required order.
+ * Since the required order is larger than any existing block,
+ * it will replace at least two existing blocks.
+ * The new set will also have minimal possible number of blocks.
+ * Therefore the new set will have at least one block less.
+ * Blocks will be updated in place and remaining blocks will be
+ * deallocated.
+ */
+
+ HGSMISIZE u32BlockSize = HGSMIMAOrder2Size(maxId);
+ HGSMISIZE cbRemaining = cbBlocks;
+ HGSMIOFFSET off = HGSMI_MA_DESC_OFFSET(pStart->descriptor);
+ HGSMIMABLOCK *pBlock = pStart;
+
+ while (u32BlockSize >= HGSMI_MA_BLOCK_SIZE_MIN && cbRemaining)
+ {
+ /* Build a list of free memory blocks with u32BlockSize. */
+ uint32_t cBlocks = cbRemaining / u32BlockSize;
+ if (cBlocks > 0)
+ {
+ HGSMIOFFSET order = HGSMIMASize2Order(u32BlockSize);
+
+ uint32_t i;
+ for (i = 0; i < cBlocks; ++i)
+ {
+ if (pBlock == pEnd)
+ {
+ /* Should never happen because the new set of blocks is supposed to be smaller. */
+ AssertFailed();
+ rc = VERR_OUT_OF_RESOURCES;
+ break;
+ }
+
+ /* Remove from the free list. */
+ RTListNodeRemove(&pBlock->nodeFree);
+
+ pBlock->descriptor = hgsmiMADescriptor(off, true, order);
+
+ RTListAppend(&pMA->aListFreeBlocks[order], &pBlock->nodeFree);
+
+ off += u32BlockSize;
+ cbRemaining -= u32BlockSize;
+
+ pBlock = RTListGetNext(&pMA->listBlocks, pBlock, HGSMIMABLOCK, nodeBlock);
+ }
+ }
+
+ if (RT_FAILURE(rc))
+ {
+ break;
+ }
+
+ u32BlockSize /= 2;
+ }
+
+ Assert(cbRemaining == 0);
+
+ if (RT_SUCCESS(rc))
+ {
+ /* Remove remaining free blocks from pBlock until pEnd */
+ for (;;)
+ {
+ bool fEnd = (pBlock == pEnd);
+ HGSMIMABLOCK *pNext = RTListGetNext(&pMA->listBlocks, pBlock, HGSMIMABLOCK, nodeBlock);
+
+ RTListNodeRemove(&pBlock->nodeFree);
+ RTListNodeRemove(&pBlock->nodeBlock);
+ --pMA->cBlocks;
+
+ hgsmiMABlockFree(pMA, pBlock);
+
+ if (fEnd)
+ {
+ break;
+ }
+
+ pBlock = pNext;
+ }
+ }
+}
+
+static void hgsmiMAQueryFreeRange(HGSMIMADATA *pMA, HGSMIMABLOCK *pBlock, HGSMISIZE cbRequired,
+ HGSMIMABLOCK **ppStart, HGSMIMABLOCK **ppEnd, HGSMISIZE *pcbBlocks)
+{
+ Assert(HGSMI_MA_DESC_IS_FREE(pBlock->descriptor));
+
+ *pcbBlocks = HGSMIMAOrder2Size(HGSMI_MA_DESC_ORDER(pBlock->descriptor));
+ *ppStart = pBlock;
+ *ppEnd = pBlock;
+
+ HGSMIMABLOCK *p;
+ for (;;)
+ {
+ p = RTListGetNext(&pMA->listBlocks, *ppEnd, HGSMIMABLOCK, nodeBlock);
+ if (!p || !HGSMI_MA_DESC_IS_FREE(p->descriptor))
+ {
+ break;
+ }
+ *pcbBlocks += HGSMIMAOrder2Size(HGSMI_MA_DESC_ORDER(p->descriptor));
+ *ppEnd = p;
+
+ if (cbRequired && *pcbBlocks >= cbRequired)
+ {
+ return;
+ }
+ }
+ for (;;)
+ {
+ p = RTListGetPrev(&pMA->listBlocks, *ppStart, HGSMIMABLOCK, nodeBlock);
+ if (!p || !HGSMI_MA_DESC_IS_FREE(p->descriptor))
+ {
+ break;
+ }
+ *pcbBlocks += HGSMIMAOrder2Size(HGSMI_MA_DESC_ORDER(p->descriptor));
+ *ppStart = p;
+
+ if (cbRequired && *pcbBlocks >= cbRequired)
+ {
+ return;
+ }
+ }
+}
+
+static void hgsmiMAMergeFreeBlocks(HGSMIMADATA *pMA, HGSMIOFFSET order)
+{
+ /* Try to create a free block with the order from smaller free blocks. */
+ if (order == 0)
+ {
+ /* No smaller blocks. */
+ return;
+ }
+
+ HGSMISIZE cbRequired = HGSMIMAOrder2Size(order);
+
+ /* Scan all free lists of smaller blocks.
+ *
+ * Get the sequence of free blocks before and after each free block.
+ * If possible, re-split the sequence to get the required block and other free block(s).
+ * If not possible, try the next free block.
+ *
+ * Free blocks are scanned from i to 0 orders.
+ */
+ HGSMIOFFSET i = order - 1;
+ for (;;)
+ {
+ HGSMIMABLOCK *pIter;
+ RTListForEach(&pMA->aListFreeBlocks[i], pIter, HGSMIMABLOCK, nodeFree)
+ {
+ Assert(HGSMI_MA_DESC_ORDER(pIter->descriptor) == i);
+
+ HGSMISIZE cbBlocks;
+ HGSMIMABLOCK *pFreeStart;
+ HGSMIMABLOCK *pFreeEnd;
+ hgsmiMAQueryFreeRange(pMA, pIter, cbRequired, &pFreeStart, &pFreeEnd, &cbBlocks);
+
+ Assert((cbBlocks / HGSMI_MA_BLOCK_SIZE_MIN) * HGSMI_MA_BLOCK_SIZE_MIN == cbBlocks);
+
+ /* Verify whether cbBlocks is enough for the requested block. */
+ if (cbBlocks >= cbRequired)
+ {
+ /* Build new free blocks starting from the requested. */
+ hgsmiMAReformatFreeBlocks(pMA, order, pFreeStart, pFreeEnd, cbBlocks);
+ i = 0; /* Leave the loop. */
+ break;
+ }
+ }
+
+ if (i == 0)
+ {
+ break;
+ }
+
+ --i;
+ }
+}
+
+static HGSMIOFFSET hgsmiMAAlloc(HGSMIMADATA *pMA, HGSMISIZE cb)
+{
+ if (cb > pMA->cbMaxBlock)
+ {
+ return HGSMIOFFSET_VOID;
+ }
+
+ if (cb < HGSMI_MA_BLOCK_SIZE_MIN)
+ {
+ cb = HGSMI_MA_BLOCK_SIZE_MIN;
+ }
+
+ HGSMIOFFSET order = HGSMIPopCnt32(cb - 1) - HGSMI_MA_DESC_ORDER_BASE;
+
+ AssertReturn(HGSMIMAOrder2Size(order) >= cb, HGSMIOFFSET_VOID);
+ AssertReturn(order < RT_ELEMENTS(pMA->aListFreeBlocks), HGSMIOFFSET_VOID);
+
+ HGSMIMABLOCK *pBlock = hgsmiMAGetFreeBlock(pMA, order);
+ if (RT_UNLIKELY(pBlock == NULL))
+ {
+ /* No free block with large enough size. Merge smaller free blocks and try again. */
+ hgsmiMAMergeFreeBlocks(pMA, order);
+ pBlock = hgsmiMAGetFreeBlock(pMA, order);
+ }
+
+ if (RT_LIKELY(pBlock != NULL))
+ {
+ RTListNodeRemove(&pBlock->nodeFree);
+ pBlock->descriptor &= ~HGSMI_MA_DESC_FREE_MASK;
+ return HGSMI_MA_DESC_OFFSET(pBlock->descriptor);
+ }
+
+ return HGSMIOFFSET_VOID;
+}
+
+static void hgsmiMAFree(HGSMIMADATA *pMA, HGSMIOFFSET off)
+{
+ if (off == HGSMIOFFSET_VOID)
+ {
+ return;
+ }
+
+ /* Find the block corresponding to the offset. */
+ Assert((off / HGSMI_MA_BLOCK_SIZE_MIN) * HGSMI_MA_BLOCK_SIZE_MIN == off);
+
+ HGSMIMABLOCK *pBlock = HGSMIMASearchOffset(pMA, off);
+ if (pBlock)
+ {
+ if (HGSMI_MA_DESC_OFFSET(pBlock->descriptor) == off)
+ {
+ /* Found the right block, mark it as free. */
+ pBlock->descriptor |= HGSMI_MA_DESC_FREE_MASK;
+ RTListAppend(&pMA->aListFreeBlocks[HGSMI_MA_DESC_ORDER(pBlock->descriptor)], &pBlock->nodeFree);
+ return;
+ }
+ }
+
+ AssertFailed();
+}
+
+int HGSMIMAInit(HGSMIMADATA *pMA, const HGSMIAREA *pArea,
+ HGSMIOFFSET *paDescriptors, uint32_t cDescriptors, HGSMISIZE cbMaxBlock,
+ const HGSMIENV *pEnv)
+{
+ AssertReturn(pArea->cbArea < UINT32_C(0x80000000), VERR_INVALID_PARAMETER);
+ AssertReturn(pArea->cbArea >= HGSMI_MA_BLOCK_SIZE_MIN, VERR_INVALID_PARAMETER);
+
+ RT_ZERO(*pMA);
+
+ HGSMISIZE cb = (pArea->cbArea / HGSMI_MA_BLOCK_SIZE_MIN) * HGSMI_MA_BLOCK_SIZE_MIN;
+
+ int rc = HGSMIAreaInitialize(&pMA->area, pArea->pu8Base, cb, 0);
+ if (RT_SUCCESS(rc))
+ {
+ pMA->env = *pEnv;
+
+ uint32_t i;
+ for (i = 0; i < RT_ELEMENTS(pMA->aListFreeBlocks); ++i)
+ {
+ RTListInit(&pMA->aListFreeBlocks[i]);
+ }
+ RTListInit(&pMA->listBlocks);
+
+ if (cDescriptors)
+ {
+ rc = hgsmiMARestore(pMA, paDescriptors, cDescriptors, cbMaxBlock);
+ }
+ else
+ {
+ rc = hgsmiMAFormat(pMA);
+ }
+
+ if (RT_SUCCESS(rc))
+ {
+ rc = hgsmiMARebuildFreeLists(pMA);
+ }
+ }
+
+ return rc;
+}
+
+void HGSMIMAUninit(HGSMIMADATA *pMA)
+{
+ HGSMIMABLOCK *pIter;
+ HGSMIMABLOCK *pNext;
+
+ RTListForEachSafe(&pMA->listBlocks, pIter, pNext, HGSMIMABLOCK, nodeBlock)
+ {
+ RTListNodeRemove(&pIter->nodeBlock);
+ hgsmiMABlockFree(pMA, pIter);
+ }
+
+ RT_ZERO(*pMA);
+}
+
+HGSMIOFFSET HGSMIMAPointerToOffset(const HGSMIMADATA *pMA, const void *pv)
+{
+ if (HGSMIAreaContainsPointer(&pMA->area, pv))
+ {
+ return HGSMIPointerToOffset(&pMA->area, pv);
+ }
+
+ AssertFailed();
+ return HGSMIOFFSET_VOID;
+}
+
+void *HGSMIMAOffsetToPointer(const HGSMIMADATA *pMA, HGSMIOFFSET off)
+{
+ if (HGSMIAreaContainsOffset(&pMA->area, off))
+ {
+ return HGSMIOffsetToPointer(&pMA->area, off);
+ }
+
+ AssertFailed();
+ return NULL;
+}
+
+void *HGSMIMAAlloc(HGSMIMADATA *pMA, HGSMISIZE cb)
+{
+ HGSMIOFFSET off = hgsmiMAAlloc(pMA, cb);
+ return HGSMIMAOffsetToPointer(pMA, off);
+}
+
+void HGSMIMAFree(HGSMIMADATA *pMA, void *pv)
+{
+ HGSMIOFFSET off = HGSMIMAPointerToOffset(pMA, pv);
+ if (off != HGSMIOFFSET_VOID)
+ {
+ hgsmiMAFree(pMA, off);
+ }
+ else
+ {
+ AssertFailed();
+ }
+}
+
+HGSMIMABLOCK *HGSMIMASearchOffset(HGSMIMADATA *pMA, HGSMIOFFSET off)
+{
+ /* Binary search in the block list for the offset. */
+ HGSMIMABLOCK *pStart = RTListGetFirst(&pMA->listBlocks, HGSMIMABLOCK, nodeBlock);
+ HGSMIMABLOCK *pEnd = RTListGetLast(&pMA->listBlocks, HGSMIMABLOCK, nodeBlock);
+ HGSMIMABLOCK *pMiddle;
+
+ uint32_t iStart = 0;
+ uint32_t iEnd = pMA->cBlocks;
+ uint32_t iMiddle;
+
+ for (;;)
+ {
+ pMiddle = pStart;
+ iMiddle = iStart + (iEnd - iStart) / 2;
+ if (iMiddle == iStart)
+ {
+ break;
+ }
+
+ /* Find the block with the iMiddle index. Never go further than pEnd. */
+ uint32_t i;
+ for (i = iStart; i < iMiddle && pMiddle != pEnd; ++i)
+ {
+ pMiddle = RTListNodeGetNext(&pMiddle->nodeBlock, HGSMIMABLOCK, nodeBlock);
+ }
+
+ HGSMIOFFSET offMiddle = HGSMI_MA_DESC_OFFSET(pMiddle->descriptor);
+ if (offMiddle > off)
+ {
+ pEnd = pMiddle;
+ iEnd = iMiddle;
+ }
+ else
+ {
+ pStart = pMiddle;
+ iStart = iMiddle;
+ }
+ }
+
+ return pMiddle;
+}
+
+
+/*
+ * Helper.
+ */
+
+uint32_t HGSMIPopCnt32(uint32_t u32)
+{
+ uint32_t c = 0;
+ if (u32 > 0xFFFF) { c += 16; u32 >>= 16; }
+ if (u32 > 0xFF) { c += 8; u32 >>= 8; }
+ if (u32 > 0xF) { c += 4; u32 >>= 4; }
+ if (u32 > 0x3) { c += 2; u32 >>= 2; }
+ if (u32 > 0x1) { c += 1; u32 >>= 1; }
+ return c + u32;
+}
--- /dev/null
+KBUILD_EXTMOD=${srctree}/ubuntu/vbox
+# $Id: Makefile.module.kms $
+## @file
+# VirtualBox Guest Additions Module Makefile.
+#
+# (For 2.6.x this file must be 'Makefile'!)
+#
+
+#
+# Copyright (C) 2006-2010 Oracle Corporation
+#
+# This file is part of VirtualBox Open Source Edition (OSE), as
+# available from http://www.virtualbox.org. This file is free software;
+# you can redistribute it and/or modify it under the terms of the GNU
+# General Public License (GPL) as published by the Free Software
+# Foundation, in version 2 as it comes in the "COPYING" file of the
+# VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+#
+
+# Linux kbuild sets this to our source directory if we are called from there
+obj ?= $(CURDIR)
+include $(obj)/Makefile.include.header
+
+MOD_NAME = vboxvideo
+
+MY_KERNELRELEASE := $(KERNELRELEASE)
+ifeq ($(MY_KERNELRELEASE),)
+ # as of 2.6.16 KERNELRELEASE is only set if the kernel is configured
+ MY_KERNELRELEASE := $(KERNELVERSION)
+endif
+ifeq ($(KERN_VERSION),24)
+ # sledgehammer, see the 2.4 handling in Makefile.include.footer
+ MY_KERNELRELEASE := 2.4.0
+endif
+ifeq ($(filter 1.% 2.% 3.0.% 3.1.% 3.2.% 3.3.% 3.4.% 3.5.% 3.6.% 3.7.% \
+3.8.% 3.9.%,$(MY_KERNELRELEASE)),)
+MOD_OBJS = HGSMIBase.o HGSMICommon.o HGSMIMemAlloc.o heapoffset.o \
+ Modesetting.o vbox_drv.o vbox_fb.o vbox_irq.o vbox_main.o \
+ vbox_mode.o vbox_ttm.o VBVABase.o vbox_prime.o
+else
+MOD_OBJS = vbox_dummy.o
+endif
+
+ifneq ($(wildcard $(KBUILD_EXTMOD)/vboxvideo),)
+ MANGLING := $(KBUILD_EXTMOD)/vboxvideo/include/VBox/VBoxGuestMangling.h
+else
+ MANGLING := $(KBUILD_EXTMOD)/include/VBox/VBoxGuestMangling.h
+endif
+MOD_CFLAGS = -Wno-declaration-after-statement -fshort-wchar -fno-pie
+ifneq ($(KERN_VERSION),24)
+MOD_CFLAGS += -include $(MANGLING)
+endif
+MOD_INCL = $(addprefix -I$(KBUILD_EXTMOD),/ /include)
+# What on earth is this?
+MOD_INCL += $(addprefix -I$(KBUILD_EXTMOD)/vboxvideo,/ /include)
+MOD_INCL += -Iinclude/drm
+MOD_DEFS := -DRT_OS_LINUX -DIN_RING0 -DIN_RT_R0 \
+ -DIN_SUP_R0 -DVBOX -DVBOX_WITH_HGCM -DLOG_TO_BACKDOOR -DIN_MODULE \
+ -DIN_GUEST_R0
+# our module does not export any symbol
+MOD_DEFS += -DRT_NO_EXPORT_SYMBOL
+ifeq ($(BUILD_TARGET_ARCH),amd64)
+ MOD_DEFS += -DRT_ARCH_AMD64 -DVBOX_WITH_64_BITS_GUESTS
+else
+ MOD_DEFS += -DRT_ARCH_X86
+endif
+MOD_CLEAN = . linux r0drv r0drv/linux
+
+include $(obj)/Makefile.include.footer
--- /dev/null
+#
+# VirtualBox Guest Additions kernel module Makefile, common parts.
+#
+# See Makefile.include.header for details of how to use this.
+#
+# Copyright (C) 2006-2015 Oracle Corporation
+#
+# This file is part of VirtualBox Open Source Edition (OSE), as
+# available from http://www.virtualbox.org. This file is free software;
+# you can redistribute it and/or modify it under the terms of the GNU
+# General Public License (GPL) as published by the Free Software
+# Foundation, in version 2 as it comes in the "COPYING" file of the
+# VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+#
+
+# override is required by the Debian guys
+override MODULE = $(MOD_NAME)
+OBJS = $(MOD_OBJS)
+
+ifneq ($(MAKECMDGOALS),clean)
+
+KBUILD_VERBOSE ?= 1
+
+#
+# Compiler options
+#
+ifndef INCL
+ INCL := $(addprefix -I,$(KERN_INCL) $(EXTRA_INCL))
+ ifndef KBUILD_EXTMOD
+ KBUILD_EXTMOD := $(shell pwd)
+ endif
+ INCL += $(MOD_INCL)
+ export INCL
+endif
+KFLAGS := -D__KERNEL__ -DMODULE $(MOD_DEFS)
+ifeq ($(BUILD_TYPE),debug)
+ KFLAGS += -DDEBUG -DDEBUG_$(subst $(subst _, ,_),_,$(USERNAME)) -DDEBUG_USERNAME=$(subst $(subst _, ,_),_,$(USERNAME))
+endif
+
+ifeq ($(KERN_VERSION), 24)
+#
+# 2.4
+#
+
+ifeq ($(BUILD_TARGET_ARCH),amd64)
+ KFLAGS += -mcmodel=kernel
+endif
+
+CFLAGS := -O2 -DVBOX_LINUX_2_4 $(MOD_CFLAGS) $(INCL) $(KFLAGS) $(MOD_EXTRA) $(KDEBUG)
+MODULE_EXT := o
+
+# 2.4 Module linking
+$(MODULE).o: $(OBJS)
+ $(LD) -o $@ -r $(OBJS)
+
+.PHONY: $(MODULE)
+all: $(MODULE)
+$(MODULE): $(MODULE).o
+
+else
+#
+# 2.6 and later
+#
+
+MODULE_EXT := ko
+
+$(MODULE)-y := $(OBJS)
+
+# build defs
+EXTRA_CFLAGS += $(MOD_CFLAGS) $(INCL) $(KFLAGS) $(MOD_EXTRA) $(KDEBUG)
+
+.PHONY: $(MODULE)
+all: $(MODULE)
+
+obj-m += $(MODULE).o
+
+JOBS := $(shell (getconf _NPROCESSORS_ONLN || grep -Ec '^processor|^CPU[0-9]' /proc/cpuinfo) 2>/dev/null)
+ifeq ($(JOBS),0)
+ JOBS := 1
+endif
+
+# OL/UEK: disable module signing for external modules -- we don't have any private key
+$(MODULE):
+ $(MAKE) KBUILD_VERBOSE=$(KBUILD_VERBOSE) CONFIG_MODULE_SIG= -C $(KERN_DIR) SUBDIRS=$(CURDIR) SRCROOT=$(CURDIR) -j$(JOBS) modules
+
+modules_install:
+ $(MAKE) KBUILD_VERBOSE=$(KBUILD_VERBOSE) CONFIG_MODULE_SIG= -C $(KERN_DIR) SUBDIRS=$(CURDIR) SRCROOT=$(CURDIR) modules_install
+
+endif
+
+install: $(MODULE)
+ @mkdir -p $(MODULE_DIR); \
+ install -m 0644 -o root -g root $(MODULE).$(MODULE_EXT) $(MODULE_DIR); \
+ PATH="$(PATH):/bin:/sbin" depmod -a;
+
+endif # eq($(MAKECMDGOALS),clean)
+
+clean:
+ for f in $(MOD_CLEAN); do rm -f $$f/*.o $$f/.*.cmd $$f/.*.flags; done
+ rm -rf .$(MOD_NAME)* .tmp_ver* $(MOD_NAME).* Modules.symvers modules.order
--- /dev/null
+#
+# VirtualBox Guest Additions kernel module Makefile, common parts.
+#
+# (For 2.6.x, the main file must be called 'Makefile'!)
+#
+# Copyright (C) 2006-2015 Oracle Corporation
+#
+# This file is part of VirtualBox Open Source Edition (OSE), as
+# available from http://www.virtualbox.org. This file is free software;
+# you can redistribute it and/or modify it under the terms of the GNU
+# General Public License (GPL) as published by the Free Software
+# Foundation, in version 2 as it comes in the "COPYING" file of the
+# VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+#
+
+# Testing:
+# * Building with KERN_VER set to an installed but non-current kernel works and
+# installs to the right location.
+# * Building with KERN_DIR and/or MODULE_DIR set uses the value specified and
+# the default value for the unspecified one if any.
+
+#
+# These file should be included by the Makefiles for any kernel modules we
+# build as part of the Guest Additions. The intended way of doing this is as
+# follows:
+#
+# # Linux kbuild sets this to our source directory if we are called from
+# # there
+# obj ?= $(CURDIR)
+# include $(obj)/Makefile.include.header
+# MOD_NAME = <name of the module to be built, without extension>
+# MOD_OBJS = <list of object files which should be included>
+# MOD_DEFS = <any additional defines which this module needs>
+# MOD_INCL = <any additional include paths which this module needs>
+# MOD_CFLAGS = <any additional CFLAGS which this module needs>
+# MOD_CLEAN = <list of directories that the clean target should look at>
+# include $(obj)/Makefile.include.footer
+#
+# The kmk kBuild define KBUILD_TARGET_ARCH is available.
+#
+
+
+#
+# First, figure out which architecture we're targeting and the build type.
+# (We have to support basic cross building (ARCH=i386|x86_64).)
+# While at it, warn about BUILD_* vars found to help with user problems.
+#
+ifeq ($(filter-out x86_64 amd64 AMD64,$(shell uname -m)),)
+ BUILD_TARGET_ARCH_DEF := amd64
+else
+ BUILD_TARGET_ARCH_DEF := x86
+endif
+ifneq ($(filter-out amd64 x86,$(BUILD_TARGET_ARCH)),)
+ $(warning Ignoring unknown BUILD_TARGET_ARCH value '$(BUILD_TARGET_ARCH)'.)
+ BUILD_TARGET_ARCH :=
+endif
+ifeq ($(BUILD_TARGET_ARCH),)
+ ifeq ($(ARCH),x86_64)
+ BUILD_TARGET_ARCH := amd64
+ else
+ ifeq ($(ARCH),i386)
+ ifeq ($(CONFIG_X86_32),y)
+ BUILD_TARGET_ARCH := x86
+ else
+ BUILD_TARGET_ARCH := amd64
+ endif
+ else
+ ifeq ($(ARCH),x86)
+ ifeq ($(CONFIG_X86_32),y)
+ BUILD_TARGET_ARCH := x86
+ else
+ BUILD_TARGET_ARCH := amd64
+ endif
+ else
+ BUILD_TARGET_ARCH := $(BUILD_TARGET_ARCH_DEF)
+ endif
+ endif
+ endif
+else
+ ifneq ($(BUILD_TARGET_ARCH),$(BUILD_TARGET_ARCH_DEF))
+ $(warning Using BUILD_TARGET_ARCH='$(BUILD_TARGET_ARCH)' from the $(origin BUILD_TARGET_ARCH).)
+ endif
+endif
+
+ifneq ($(filter-out release profile debug strict,$(BUILD_TYPE)),)
+ $(warning Ignoring unknown BUILD_TYPE value '$(BUILD_TYPE)'.)
+ BUILD_TYPE :=
+endif
+ifeq ($(BUILD_TYPE),)
+ BUILD_TYPE := release
+else
+ ifneq ($(BUILD_TYPE),release)
+ $(warning Using BUILD_TYPE='$(BUILD_TYPE)' from the $(origin BUILD_TYPE).)
+ endif
+endif
+ifeq ($(USERNAME),)
+ USERNAME := noname
+endif
+
+ifneq ($(MAKECMDGOALS),clean)
+
+ifeq ($(KERNELRELEASE),)
+
+ #
+ # building from this directory
+ #
+
+ # target kernel version
+ ifndef KERN_VER
+ KERN_VER := $(shell uname -r)
+ else
+ ifneq ($(shell if test -d /lib/modules/$(KERN_VER)/build; then echo yes; fi),yes)
+ KERN_VER := $(shell uname -r)
+ endif
+ endif
+
+ # kernel base directory
+ ifndef KERN_DIR
+ KERN_DIR := /lib/modules/$(KERN_VER)/build
+ ifneq ($(shell if test -d $(KERN_DIR); then echo yes; fi),yes)
+ KERN_DIR := /usr/src/linux
+ ifneq ($(shell if test -d $(KERN_DIR); then echo yes; fi),yes)
+ $(error Error: unable to find the sources of your current Linux kernel. \
+ Specify KERN_DIR=<directory> and run Make again)
+ endif
+ $(warning Warning: using /usr/src/linux as the source directory of your \
+ Linux kernel. If this is not correct, specify \
+ KERN_DIR=<directory> and run Make again.)
+ endif
+ else
+ ifneq ($(shell if test -d $(KERN_DIR); then echo yes; fi),yes)
+ $(error Error: KERN_DIR does not point to a directory)
+ endif
+ endif
+
+ # includes
+ ifndef KERN_INCL
+ KERN_INCL = $(KERN_DIR)/include
+ endif
+ ifneq ($(shell if test -d $(KERN_INCL); then echo yes; fi),yes)
+ $(error Error: unable to find the include directory for your current Linux \
+ kernel. Specify KERN_INCL=<directory> and run Make again)
+ endif
+
+ # module install dir, only for current kernel
+ ifneq ($(filter install install_rpm,$(MAKECMDGOALS)),)
+ ifndef MODULE_DIR
+ MODULE_DIR_TST := /lib/modules/$(KERN_VER)
+ ifeq ($(shell if test -d $(MODULE_DIR_TST); then echo yes; fi),yes)
+ MODULE_DIR := $(MODULE_DIR_TST)/misc
+ else
+ $(error Unable to find the folder to install the module to)
+ endif
+ endif # MODULE_DIR unspecified
+ endif
+
+ # guess kernel version (24 or 26)
+ ifeq ($(shell if grep '"2\.4\.' $(KERN_INCL)/linux/version.h > /dev/null; then echo yes; fi),yes)
+ KERN_VERSION := 24
+ else
+ KERN_VERSION := 26
+ endif
+
+else # neq($(KERNELRELEASE),)
+
+ #
+ # building from kbuild (make -C <kernel_directory> M=`pwd`)
+ #
+
+ # guess kernel version (24 or 26)
+ ifeq ($(shell if echo "$(VERSION).$(PATCHLEVEL)." | grep '2\.4\.' > /dev/null; then echo yes; fi),yes)
+ KERN_VERSION := 24
+ else
+ KERN_VERSION := 26
+ endif
+
+endif # neq($(KERNELRELEASE),)
+
+# debug - show guesses.
+ifdef DEBUG
+$(warning dbg: KERN_DIR = $(KERN_DIR))
+$(warning dbg: KERN_INCL = $(KERN_INCL))
+$(warning dbg: MODULE_DIR = $(MODULE_DIR))
+$(warning dbg: KERN_VERSION = $(KERN_VERSION))
+endif
+
+endif # eq($(MAKECMDGOALS),clean)
--- /dev/null
+/* $Id: Modesetting.cpp $ */
+/** @file
+ * VirtualBox Video driver, common code - HGSMI initialisation and helper
+ * functions.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include <VBox/VBoxVideoGuest.h>
+#include <VBox/VBoxVideo.h>
+#include <VBox/VBoxGuest.h>
+#include <VBox/Hardware/VBoxVideoVBE.h>
+#include <VBox/VMMDev.h>
+
+#include <iprt/asm.h>
+#include <iprt/log.h>
+
+#ifndef VBOX_GUESTR3XF86MOD
+# include <iprt/string.h>
+#endif
+
+/**
+ * Gets the count of virtual monitors attached to the guest via an HGSMI
+ * command
+ *
+ * @returns the right count on success or 1 on failure.
+ * @param pCtx the context containing the heap to use
+ */
+DECLHIDDEN(uint32_t) VBoxHGSMIGetMonitorCount(PHGSMIGUESTCOMMANDCONTEXT pCtx)
+{
+ /* Query the configured number of displays. */
+ uint32_t cDisplays = 0;
+ VBoxQueryConfHGSMI(pCtx, VBOX_VBVA_CONF32_MONITOR_COUNT, &cDisplays);
+ LogFunc(("cDisplays = %d\n", cDisplays));
+ if (cDisplays == 0 || cDisplays > VBOX_VIDEO_MAX_SCREENS)
+ /* Host reported some bad value. Continue in the 1 screen mode. */
+ cDisplays = 1;
+ return cDisplays;
+}
+
+
+/**
+ * Returns the size of the video RAM in bytes.
+ *
+ * @returns the size
+ */
+DECLHIDDEN(uint32_t) VBoxVideoGetVRAMSize(void)
+{
+ /** @note A 32bit read on this port returns the VRAM size. */
+ return VBoxVideoCmnPortReadUlong(VBE_DISPI_IOPORT_DATA);
+}
+
+
+/**
+ * Check whether this hardware allows the display width to have non-multiple-
+ * of-eight values.
+ *
+ * @returns true if any width is allowed, false otherwise.
+ */
+DECLHIDDEN(bool) VBoxVideoAnyWidthAllowed(void)
+{
+ unsigned DispiId;
+ VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
+ VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID_ANYX);
+ DispiId = VBoxVideoCmnPortReadUshort(VBE_DISPI_IOPORT_DATA);
+ return (DispiId == VBE_DISPI_ID_ANYX);
+}
+
+
+/**
+ * Tell the host about how VRAM is divided up between each screen via an HGSMI
+ * command. It is acceptable to specifiy identical data for each screen if
+ * they share a single framebuffer.
+ *
+ * @returns iprt status code, either VERR_NO_MEMORY or the status returned by
+ * @a pfnFill
+ * @todo What was I thinking of with that callback function? It
+ * would be much simpler to just pass in a structure in normal
+ * memory and copy it.
+ * @param pCtx the context containing the heap to use
+ * @param u32Count the number of screens we are activating
+ * @param pfnFill a callback which initialises the VBVAINFOVIEW structures
+ * for all screens
+ * @param pvData context data for @a pfnFill
+ */
+DECLHIDDEN(int) VBoxHGSMISendViewInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx,
+ uint32_t u32Count,
+ PFNHGSMIFILLVIEWINFO pfnFill,
+ void *pvData)
+{
+ int rc;
+ /* Issue the screen info command. */
+ void *p = VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVAINFOVIEW) * u32Count,
+ HGSMI_CH_VBVA, VBVA_INFO_VIEW);
+ if (p)
+ {
+ VBVAINFOVIEW *pInfo = (VBVAINFOVIEW *)p;
+ rc = pfnFill(pvData, pInfo, u32Count);
+ if (RT_SUCCESS(rc))
+ VBoxHGSMIBufferSubmit (pCtx, p);
+ VBoxHGSMIBufferFree(pCtx, p);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ return rc;
+}
+
+
+/**
+ * Set a video mode using port registers. This must be done for the first
+ * screen before every HGSMI modeset and also works when HGSM is not enabled.
+ * @param cWidth the mode width
+ * @param cHeight the mode height
+ * @param cVirtWidth the mode pitch
+ * @param cBPP the colour depth of the mode
+ * @param fFlags flags for the mode. These will be or-ed with the
+ * default _ENABLED flag, so unless you are restoring
+ * a saved mode or have special requirements you can pass
+ * zero here.
+ * @param cx the horizontal panning offset
+ * @param cy the vertical panning offset
+ */
+DECLHIDDEN(void) VBoxVideoSetModeRegisters(uint16_t cWidth, uint16_t cHeight,
+ uint16_t cVirtWidth, uint16_t cBPP,
+ uint16_t fFlags, uint16_t cx,
+ uint16_t cy)
+{
+ /* set the mode characteristics */
+ VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
+ VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_DATA, cWidth);
+ VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
+ VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_DATA, cHeight);
+ VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX,
+ VBE_DISPI_INDEX_VIRT_WIDTH);
+ VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_DATA, cVirtWidth);
+ VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
+ VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_DATA, cBPP);
+ /* enable the mode */
+ VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX,
+ VBE_DISPI_INDEX_ENABLE);
+ VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_DATA,
+ fFlags | VBE_DISPI_ENABLED);
+ /* Panning registers */
+ VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX,
+ VBE_DISPI_INDEX_X_OFFSET);
+ VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_DATA, cx);
+ VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX,
+ VBE_DISPI_INDEX_Y_OFFSET);
+ VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_DATA, cy);
+ /** @todo read from the port to see if the mode switch was successful */
+}
+
+
+/**
+ * Get the video mode for the first screen using the port registers. All
+ * parameters are optional
+ * @returns true if the VBE mode returned is active, false if we are in VGA
+ * mode
+ * @note If anyone else needs additional register values just extend the
+ * function with additional parameters and fix any existing callers.
+ * @param pcWidth where to store the mode width
+ * @param pcHeight where to store the mode height
+ * @param pcVirtWidth where to store the mode pitch
+ * @param pcBPP where to store the colour depth of the mode
+ * @param pfFlags where to store the flags for the mode
+ */
+DECLHIDDEN(bool) VBoxVideoGetModeRegisters(uint16_t *pcWidth, uint16_t *pcHeight,
+ uint16_t *pcVirtWidth, uint16_t *pcBPP,
+ uint16_t *pfFlags)
+{
+ uint16_t fFlags;
+
+ VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX,
+ VBE_DISPI_INDEX_ENABLE);
+ fFlags = VBoxVideoCmnPortReadUshort(VBE_DISPI_IOPORT_DATA);
+ if (pcWidth)
+ {
+ VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX,
+ VBE_DISPI_INDEX_XRES);
+ *pcWidth = VBoxVideoCmnPortReadUshort(VBE_DISPI_IOPORT_DATA);
+ }
+ if (pcHeight)
+ {
+ VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX,
+ VBE_DISPI_INDEX_YRES);
+ *pcHeight = VBoxVideoCmnPortReadUshort(VBE_DISPI_IOPORT_DATA);
+ }
+ if (pcVirtWidth)
+ {
+ VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX,
+ VBE_DISPI_INDEX_VIRT_WIDTH);
+ *pcVirtWidth = VBoxVideoCmnPortReadUshort(VBE_DISPI_IOPORT_DATA);
+ }
+ if (pcBPP)
+ {
+ VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX,
+ VBE_DISPI_INDEX_BPP);
+ *pcBPP = VBoxVideoCmnPortReadUshort(VBE_DISPI_IOPORT_DATA);
+ }
+ if (pfFlags)
+ *pfFlags = fFlags;
+ return RT_BOOL(fFlags & VBE_DISPI_ENABLED);
+}
+
+
+/**
+ * Disable our extended graphics mode and go back to VGA mode.
+ */
+DECLHIDDEN(void) VBoxVideoDisableVBE(void)
+{
+ VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX,
+ VBE_DISPI_INDEX_ENABLE);
+ VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_DATA, 0);
+}
+
+
+/**
+ * Set a video mode via an HGSMI request. The views must have been
+ * initialised first using @a VBoxHGSMISendViewInfo and if the mode is being
+ * set on the first display then it must be set first using registers.
+ * @param cDisplay the screen number
+ * @param cOriginX the horizontal displacement relative to the first screen
+ * @param cOriginY the vertical displacement relative to the first screen
+ * @param offStart the offset of the visible area of the framebuffer
+ * relative to the framebuffer start
+ * @param cbPitch the offset in bytes between the starts of two adjecent
+ * scan lines in video RAM
+ * @param cWidth the mode width
+ * @param cHeight the mode height
+ * @param cBPP the colour depth of the mode
+ */
+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)
+{
+ /* Issue the screen info command. */
+ void *p = VBoxHGSMIBufferAlloc(pCtx,
+ sizeof (VBVAINFOSCREEN),
+ HGSMI_CH_VBVA,
+ VBVA_INFO_SCREEN);
+ if (!p)
+ {
+ LogFunc(("HGSMIHeapAlloc failed\n"));
+ }
+ else
+ {
+ VBVAINFOSCREEN *pScreen = (VBVAINFOSCREEN *)p;
+
+ pScreen->u32ViewIndex = cDisplay;
+ pScreen->i32OriginX = cOriginX;
+ pScreen->i32OriginY = cOriginY;
+ pScreen->u32StartOffset = offStart;
+ pScreen->u32LineSize = cbPitch;
+ pScreen->u32Width = cWidth;
+ pScreen->u32Height = cHeight;
+ pScreen->u16BitsPerPixel = cBPP;
+ pScreen->u16Flags = fFlags;
+
+ VBoxHGSMIBufferSubmit(pCtx, p);
+
+ VBoxHGSMIBufferFree(pCtx, p);
+ }
+}
+
+
+/** 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.
+ * @param pCtx The context containing the heap to use.
+ * @param cOriginX Upper left X co-ordinate relative to the first screen.
+ * @param cOriginY Upper left Y co-ordinate relative to the first screen.
+ * @param cWidth Rectangle width.
+ * @param cHeight Rectangle height.
+ * @returns iprt status code.
+ * @returns VERR_NO_MEMORY HGSMI heap allocation failed.
+ */
+DECLHIDDEN(int) VBoxHGSMIUpdateInputMapping(PHGSMIGUESTCOMMANDCONTEXT pCtx, int32_t cOriginX, int32_t cOriginY,
+ uint32_t cWidth, uint32_t cHeight)
+{
+ int rc = VINF_SUCCESS;
+ VBVAREPORTINPUTMAPPING *p;
+ Log(("%s: cOriginX=%d, cOriginY=%d, cWidth=%u, cHeight=%u\n", __PRETTY_FUNCTION__, (int)cOriginX, (int)cOriginX,
+ (unsigned)cWidth, (unsigned)cHeight));
+
+ /* Allocate the IO buffer. */
+ p = (VBVAREPORTINPUTMAPPING *)VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVAREPORTINPUTMAPPING), HGSMI_CH_VBVA,
+ VBVA_REPORT_INPUT_MAPPING);
+ if (p)
+ {
+ /* Prepare data to be sent to the host. */
+ p->x = cOriginX;
+ p->y = cOriginY;
+ p->cx = cWidth;
+ p->cy = cHeight;
+ rc = VBoxHGSMIBufferSubmit(pCtx, p);
+ /* Free the IO buffer. */
+ VBoxHGSMIBufferFree(pCtx, p);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ LogFunc(("rc = %d\n", rc));
+ return rc;
+}
+
+
+/**
+ * Get most recent video mode hints.
+ * @param pCtx the context containing the heap to use
+ * @param cScreens the number of screens to query hints for, starting at 0.
+ * @param pHints array of VBVAMODEHINT structures for receiving the hints.
+ * @returns iprt status code
+ * @returns VERR_NO_MEMORY HGSMI heap allocation failed.
+ * @returns VERR_NOT_SUPPORTED Host does not support this command.
+ */
+DECLHIDDEN(int) VBoxHGSMIGetModeHints(PHGSMIGUESTCOMMANDCONTEXT pCtx,
+ unsigned cScreens, VBVAMODEHINT *paHints)
+{
+ int rc;
+ AssertPtrReturn(paHints, VERR_INVALID_POINTER);
+ void *p = VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVAQUERYMODEHINTS)
+ + cScreens * sizeof(VBVAMODEHINT),
+ HGSMI_CH_VBVA, VBVA_QUERY_MODE_HINTS);
+ if (!p)
+ {
+ LogFunc(("HGSMIHeapAlloc failed\n"));
+ return VERR_NO_MEMORY;
+ }
+ else
+ {
+ VBVAQUERYMODEHINTS *pQuery = (VBVAQUERYMODEHINTS *)p;
+
+ pQuery->cHintsQueried = cScreens;
+ pQuery->cbHintStructureGuest = sizeof(VBVAMODEHINT);
+ pQuery->rc = VERR_NOT_SUPPORTED;
+
+ VBoxHGSMIBufferSubmit(pCtx, p);
+ rc = pQuery->rc;
+ if (RT_SUCCESS(rc))
+ memcpy(paHints, ((uint8_t *)p) + sizeof(VBVAQUERYMODEHINTS),
+ cScreens * sizeof(VBVAMODEHINT));
+
+ VBoxHGSMIBufferFree(pCtx, p);
+ }
+ return rc;
+}
+
+
+/**
+ * Query the supported flags in VBVAINFOSCREEN::u16Flags.
+ *
+ * @returns The mask of VBVA_SCREEN_F_* flags or 0 if host does not support the request.
+ * @param pCtx the context containing the heap to use
+ */
+DECLHIDDEN(uint16_t) VBoxHGSMIGetScreenFlags(PHGSMIGUESTCOMMANDCONTEXT pCtx)
+{
+ uint32_t u32Flags = 0;
+ int rc = VBoxQueryConfHGSMIDef(pCtx, VBOX_VBVA_CONF32_SCREEN_FLAGS, 0, &u32Flags);
+ LogFunc(("u32Flags = 0x%x rc %Rrc\n", u32Flags, rc));
+ if (RT_FAILURE(rc))
+ u32Flags = 0;
+ return (uint16_t)u32Flags;
+}
--- /dev/null
+/* $Id: VBVABase.cpp $ */
+/** @file
+ * VirtualBox Video driver, common code - VBVA initialisation and helper
+ * functions.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include <VBox/VBoxVideoGuest.h>
+#include <VBox/VBoxVideo.h>
+#include <VBox/err.h>
+#include <VBox/log.h>
+#include <iprt/assert.h>
+#include <iprt/string.h>
+
+/*
+ * There is a hardware ring buffer in the graphics device video RAM, formerly
+ * in the VBox VMMDev PCI memory space.
+ * All graphics commands go there serialized by VBoxVBVABufferBeginUpdate.
+ * and vboxHwBufferEndUpdate.
+ *
+ * off32Free is writing position. off32Data is reading position.
+ * off32Free == off32Data means buffer is empty.
+ * There must be always gap between off32Data and off32Free when data
+ * are in the buffer.
+ * Guest only changes off32Free, host changes off32Data.
+ */
+
+/* Forward declarations of internal functions. */
+static void vboxHwBufferFlush(PHGSMIGUESTCOMMANDCONTEXT pCtx);
+static void vboxHwBufferPlaceDataAt(PVBVABUFFERCONTEXT pCtx, const void *p,
+ uint32_t cb, uint32_t offset);
+static bool vboxHwBufferWrite(PVBVABUFFERCONTEXT pCtx,
+ PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
+ const void *p, uint32_t cb);
+
+
+static bool vboxVBVAInformHost(PVBVABUFFERCONTEXT pCtx,
+ PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
+ int32_t cScreen, bool bEnable)
+{
+ bool bRc = false;
+
+#if 0 /* All callers check this */
+ if (ppdev->bHGSMISupported)
+#endif
+ {
+ void *p = VBoxHGSMIBufferAlloc(pHGSMICtx,
+ sizeof (VBVAENABLE_EX),
+ HGSMI_CH_VBVA,
+ VBVA_ENABLE);
+ if (!p)
+ {
+ LogFunc(("HGSMIHeapAlloc failed\n"));
+ }
+ else
+ {
+ VBVAENABLE_EX *pEnable = (VBVAENABLE_EX *)p;
+
+ pEnable->Base.u32Flags = bEnable? VBVA_F_ENABLE: VBVA_F_DISABLE;
+ pEnable->Base.u32Offset = pCtx->offVRAMBuffer;
+ pEnable->Base.i32Result = VERR_NOT_SUPPORTED;
+ if (cScreen >= 0)
+ {
+ pEnable->Base.u32Flags |= VBVA_F_EXTENDED | VBVA_F_ABSOFFSET;
+ pEnable->u32ScreenId = cScreen;
+ }
+
+ VBoxHGSMIBufferSubmit(pHGSMICtx, p);
+
+ if (bEnable)
+ {
+ bRc = RT_SUCCESS(pEnable->Base.i32Result);
+ }
+ else
+ {
+ bRc = true;
+ }
+
+ VBoxHGSMIBufferFree(pHGSMICtx, p);
+ }
+ }
+
+ return bRc;
+}
+
+/*
+ * Public hardware buffer methods.
+ */
+DECLHIDDEN(bool) VBoxVBVAEnable(PVBVABUFFERCONTEXT pCtx,
+ PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
+ VBVABUFFER *pVBVA, int32_t cScreen)
+{
+ bool bRc = false;
+
+ LogFlowFunc(("pVBVA %p\n", pVBVA));
+
+#if 0 /* All callers check this */
+ if (ppdev->bHGSMISupported)
+#endif
+ {
+ LogFunc(("pVBVA %p vbva off 0x%x\n", pVBVA, pCtx->offVRAMBuffer));
+
+ pVBVA->hostFlags.u32HostEvents = 0;
+ pVBVA->hostFlags.u32SupportedOrders = 0;
+ pVBVA->off32Data = 0;
+ pVBVA->off32Free = 0;
+ memset(pVBVA->aRecords, 0, sizeof (pVBVA->aRecords));
+ pVBVA->indexRecordFirst = 0;
+ pVBVA->indexRecordFree = 0;
+ pVBVA->cbPartialWriteThreshold = 256;
+ pVBVA->cbData = pCtx->cbBuffer - sizeof (VBVABUFFER) + sizeof (pVBVA->au8Data);
+
+ pCtx->fHwBufferOverflow = false;
+ pCtx->pRecord = NULL;
+ pCtx->pVBVA = pVBVA;
+
+ bRc = vboxVBVAInformHost(pCtx, pHGSMICtx, cScreen, true);
+ }
+
+ if (!bRc)
+ {
+ VBoxVBVADisable(pCtx, pHGSMICtx, cScreen);
+ }
+
+ return bRc;
+}
+
+DECLHIDDEN(void) VBoxVBVADisable(PVBVABUFFERCONTEXT pCtx,
+ PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
+ int32_t cScreen)
+{
+ LogFlowFunc(("\n"));
+
+ pCtx->fHwBufferOverflow = false;
+ pCtx->pRecord = NULL;
+ pCtx->pVBVA = NULL;
+
+ vboxVBVAInformHost(pCtx, pHGSMICtx, cScreen, false);
+
+ return;
+}
+
+DECLHIDDEN(bool) VBoxVBVABufferBeginUpdate(PVBVABUFFERCONTEXT pCtx,
+ PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx)
+{
+ bool bRc = false;
+
+ // LogFunc(("flags = 0x%08X\n", pCtx->pVBVA? pCtx->pVBVA->u32HostEvents: -1));
+
+ if ( pCtx->pVBVA
+ && (pCtx->pVBVA->hostFlags.u32HostEvents & VBVA_F_MODE_ENABLED))
+ {
+ uint32_t indexRecordNext;
+
+ Assert(!pCtx->fHwBufferOverflow);
+ Assert(pCtx->pRecord == NULL);
+
+ indexRecordNext = (pCtx->pVBVA->indexRecordFree + 1) % VBVA_MAX_RECORDS;
+
+ if (indexRecordNext == pCtx->pVBVA->indexRecordFirst)
+ {
+ /* All slots in the records queue are used. */
+ vboxHwBufferFlush (pHGSMICtx);
+ }
+
+ if (indexRecordNext == pCtx->pVBVA->indexRecordFirst)
+ {
+ /* Even after flush there is no place. Fail the request. */
+ LogFunc(("no space in the queue of records!!! first %d, last %d\n",
+ pCtx->pVBVA->indexRecordFirst, pCtx->pVBVA->indexRecordFree));
+ }
+ else
+ {
+ /* Initialize the record. */
+ VBVARECORD *pRecord = &pCtx->pVBVA->aRecords[pCtx->pVBVA->indexRecordFree];
+
+ pRecord->cbRecord = VBVA_F_RECORD_PARTIAL;
+
+ pCtx->pVBVA->indexRecordFree = indexRecordNext;
+
+ // LogFunc(("indexRecordNext = %d\n", indexRecordNext));
+
+ /* Remember which record we are using. */
+ pCtx->pRecord = pRecord;
+
+ bRc = true;
+ }
+ }
+
+ return bRc;
+}
+
+DECLHIDDEN(void) VBoxVBVABufferEndUpdate(PVBVABUFFERCONTEXT pCtx)
+{
+ VBVARECORD *pRecord;
+
+ // LogFunc(("\n"));
+
+ Assert(pCtx->pVBVA);
+
+ pRecord = pCtx->pRecord;
+ Assert(pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL));
+
+ /* Mark the record completed. */
+ pRecord->cbRecord &= ~VBVA_F_RECORD_PARTIAL;
+
+ pCtx->fHwBufferOverflow = false;
+ pCtx->pRecord = NULL;
+
+ return;
+}
+
+/*
+ * Private operations.
+ */
+static uint32_t vboxHwBufferAvail (const VBVABUFFER *pVBVA)
+{
+ int32_t i32Diff = pVBVA->off32Data - pVBVA->off32Free;
+
+ return i32Diff > 0? i32Diff: pVBVA->cbData + i32Diff;
+}
+
+static void vboxHwBufferFlush(PHGSMIGUESTCOMMANDCONTEXT pCtx)
+{
+ /* Issue the flush command. */
+ void *p = VBoxHGSMIBufferAlloc(pCtx,
+ sizeof (VBVAFLUSH),
+ HGSMI_CH_VBVA,
+ VBVA_FLUSH);
+ if (!p)
+ {
+ LogFunc(("HGSMIHeapAlloc failed\n"));
+ }
+ else
+ {
+ VBVAFLUSH *pFlush = (VBVAFLUSH *)p;
+
+ pFlush->u32Reserved = 0;
+
+ VBoxHGSMIBufferSubmit(pCtx, p);
+
+ VBoxHGSMIBufferFree(pCtx, p);
+ }
+
+ return;
+}
+
+static void vboxHwBufferPlaceDataAt(PVBVABUFFERCONTEXT pCtx, const void *p,
+ uint32_t cb, uint32_t offset)
+{
+ VBVABUFFER *pVBVA = pCtx->pVBVA;
+ uint32_t u32BytesTillBoundary = pVBVA->cbData - offset;
+ uint8_t *dst = &pVBVA->au8Data[offset];
+ int32_t i32Diff = cb - u32BytesTillBoundary;
+
+ if (i32Diff <= 0)
+ {
+ /* Chunk will not cross buffer boundary. */
+ memcpy (dst, p, cb);
+ }
+ else
+ {
+ /* Chunk crosses buffer boundary. */
+ memcpy (dst, p, u32BytesTillBoundary);
+ memcpy (&pVBVA->au8Data[0], (uint8_t *)p + u32BytesTillBoundary, i32Diff);
+ }
+
+ return;
+}
+
+static bool vboxHwBufferWrite(PVBVABUFFERCONTEXT pCtx,
+ PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
+ const void *p, uint32_t cb)
+{
+ VBVARECORD *pRecord;
+ uint32_t cbHwBufferAvail;
+
+ uint32_t cbWritten = 0;
+
+ VBVABUFFER *pVBVA = pCtx->pVBVA;
+ Assert(pVBVA);
+
+ if (!pVBVA || pCtx->fHwBufferOverflow)
+ {
+ return false;
+ }
+
+ Assert(pVBVA->indexRecordFirst != pVBVA->indexRecordFree);
+
+ pRecord = pCtx->pRecord;
+ Assert(pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL));
+
+ // LogFunc(("%d\n", cb));
+
+ cbHwBufferAvail = vboxHwBufferAvail (pVBVA);
+
+ while (cb > 0)
+ {
+ uint32_t cbChunk = cb;
+
+ // LogFunc(("pVBVA->off32Free %d, pRecord->cbRecord 0x%08X, cbHwBufferAvail %d, cb %d, cbWritten %d\n",
+ // pVBVA->off32Free, pRecord->cbRecord, cbHwBufferAvail, cb, cbWritten));
+
+ if (cbChunk >= cbHwBufferAvail)
+ {
+ LogFunc(("1) avail %d, chunk %d\n", cbHwBufferAvail, cbChunk));
+
+ vboxHwBufferFlush (pHGSMICtx);
+
+ cbHwBufferAvail = vboxHwBufferAvail (pVBVA);
+
+ if (cbChunk >= cbHwBufferAvail)
+ {
+ LogFunc(("no place for %d bytes. Only %d bytes available after flush. Going to partial writes.\n",
+ cb, cbHwBufferAvail));
+
+ if (cbHwBufferAvail <= pVBVA->cbPartialWriteThreshold)
+ {
+ LogFunc(("Buffer overflow!!!\n"));
+ pCtx->fHwBufferOverflow = true;
+ Assert(false);
+ return false;
+ }
+
+ cbChunk = cbHwBufferAvail - pVBVA->cbPartialWriteThreshold;
+ }
+ }
+
+ Assert(cbChunk <= cb);
+ Assert(cbChunk <= vboxHwBufferAvail (pVBVA));
+
+ vboxHwBufferPlaceDataAt (pCtx, (uint8_t *)p + cbWritten, cbChunk, pVBVA->off32Free);
+
+ pVBVA->off32Free = (pVBVA->off32Free + cbChunk) % pVBVA->cbData;
+ pRecord->cbRecord += cbChunk;
+ cbHwBufferAvail -= cbChunk;
+
+ cb -= cbChunk;
+ cbWritten += cbChunk;
+ }
+
+ return true;
+}
+
+/*
+ * Public writer to the hardware buffer.
+ */
+DECLHIDDEN(bool) VBoxVBVAWrite(PVBVABUFFERCONTEXT pCtx,
+ PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
+ const void *pv, uint32_t cb)
+{
+ return vboxHwBufferWrite (pCtx, pHGSMICtx, pv, cb);
+}
+
+DECLHIDDEN(bool) VBoxVBVAOrderSupported(PVBVABUFFERCONTEXT pCtx, unsigned code)
+{
+ VBVABUFFER *pVBVA = pCtx->pVBVA;
+
+ if (!pVBVA)
+ {
+ return false;
+ }
+
+ if (pVBVA->hostFlags.u32SupportedOrders & (1 << code))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+DECLHIDDEN(void) VBoxVBVASetupBufferContext(PVBVABUFFERCONTEXT pCtx,
+ uint32_t offVRAMBuffer,
+ uint32_t cbBuffer)
+{
+ pCtx->offVRAMBuffer = offVRAMBuffer;
+ pCtx->cbBuffer = cbBuffer;
+}
--- /dev/null
+/* $Id: heapoffset.cpp $ */
+/** @file
+ * IPRT - An Offset Based Heap.
+ */
+
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP RTLOGGROUP_DEFAULT
+#include <iprt/heap.h>
+#include "internal/iprt.h"
+
+#include <iprt/assert.h>
+#include <iprt/asm.h>
+#include <iprt/err.h>
+#include <iprt/log.h>
+#include <iprt/param.h>
+#include <iprt/string.h>
+
+#include "internal/magics.h"
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/** Pointer to the heap anchor block. */
+typedef struct RTHEAPOFFSETINTERNAL *PRTHEAPOFFSETINTERNAL;
+/** Pointer to a heap block. */
+typedef struct RTHEAPOFFSETBLOCK *PRTHEAPOFFSETBLOCK;
+/** Pointer to a free heap block. */
+typedef struct RTHEAPOFFSETFREE *PRTHEAPOFFSETFREE;
+
+/**
+ * Structure describing a block in an offset based heap.
+ *
+ * If this block is allocated, it is followed by the user data.
+ * If this block is free, see RTHEAPOFFSETFREE.
+ */
+typedef struct RTHEAPOFFSETBLOCK
+{
+ /** The next block in the global block list. */
+ uint32_t /*PRTHEAPOFFSETBLOCK*/ offNext;
+ /** The previous block in the global block list. */
+ uint32_t /*PRTHEAPOFFSETBLOCK*/ offPrev;
+ /** Offset into the heap of this block. Used to locate the anchor block. */
+ uint32_t /*PRTHEAPOFFSETINTERNAL*/ offSelf;
+ /** Flags + magic. */
+ uint32_t fFlags;
+} RTHEAPOFFSETBLOCK;
+AssertCompileSize(RTHEAPOFFSETBLOCK, 16);
+
+/** The block is free if this flag is set. When cleared it's allocated. */
+#define RTHEAPOFFSETBLOCK_FLAGS_FREE (RT_BIT_32(0))
+/** The magic value. */
+#define RTHEAPOFFSETBLOCK_FLAGS_MAGIC (UINT32_C(0xabcdef00))
+/** The mask that needs to be applied to RTHEAPOFFSETBLOCK::fFlags to obtain the magic value. */
+#define RTHEAPOFFSETBLOCK_FLAGS_MAGIC_MASK (~RT_BIT_32(0))
+
+/**
+ * Checks if the specified block is valid or not.
+ * @returns boolean answer.
+ * @param pBlock Pointer to a RTHEAPOFFSETBLOCK structure.
+ */
+#define RTHEAPOFFSETBLOCK_IS_VALID(pBlock) \
+ ( ((pBlock)->fFlags & RTHEAPOFFSETBLOCK_FLAGS_MAGIC_MASK) == RTHEAPOFFSETBLOCK_FLAGS_MAGIC )
+
+/**
+ * Checks if the specified block is valid and in use.
+ * @returns boolean answer.
+ * @param pBlock Pointer to a RTHEAPOFFSETBLOCK structure.
+ */
+#define RTHEAPOFFSETBLOCK_IS_VALID_USED(pBlock) \
+ ( ((pBlock)->fFlags & (RTHEAPOFFSETBLOCK_FLAGS_MAGIC_MASK | RTHEAPOFFSETBLOCK_FLAGS_FREE)) \
+ == RTHEAPOFFSETBLOCK_FLAGS_MAGIC )
+
+/**
+ * Checks if the specified block is valid and free.
+ * @returns boolean answer.
+ * @param pBlock Pointer to a RTHEAPOFFSETBLOCK structure.
+ */
+#define RTHEAPOFFSETBLOCK_IS_VALID_FREE(pBlock) \
+ ( ((pBlock)->fFlags & (RTHEAPOFFSETBLOCK_FLAGS_MAGIC_MASK | RTHEAPOFFSETBLOCK_FLAGS_FREE)) \
+ == (RTHEAPOFFSETBLOCK_FLAGS_MAGIC | RTHEAPOFFSETBLOCK_FLAGS_FREE) )
+
+/**
+ * Checks if the specified block is free or not.
+ * @returns boolean answer.
+ * @param pBlock Pointer to a valid RTHEAPOFFSETBLOCK structure.
+ */
+#define RTHEAPOFFSETBLOCK_IS_FREE(pBlock) (!!((pBlock)->fFlags & RTHEAPOFFSETBLOCK_FLAGS_FREE))
+
+/**
+ * A free heap block.
+ * This is an extended version of RTHEAPOFFSETBLOCK that takes the unused
+ * user data to store free list pointers and a cached size value.
+ */
+typedef struct RTHEAPOFFSETFREE
+{
+ /** Core stuff. */
+ RTHEAPOFFSETBLOCK Core;
+ /** Pointer to the next free block. */
+ uint32_t /*PRTHEAPOFFSETFREE*/ offNext;
+ /** Pointer to the previous free block. */
+ uint32_t /*PRTHEAPOFFSETFREE*/ offPrev;
+ /** The size of the block (excluding the RTHEAPOFFSETBLOCK part). */
+ uint32_t cb;
+ /** An alignment filler to make it a multiple of 16 bytes. */
+ uint32_t Alignment;
+} RTHEAPOFFSETFREE;
+AssertCompileSize(RTHEAPOFFSETFREE, 16+16);
+
+
+/**
+ * The heap anchor block.
+ * This structure is placed at the head of the memory block specified to RTHeapOffsetInit(),
+ * which means that the first RTHEAPOFFSETBLOCK appears immediately after this structure.
+ */
+typedef struct RTHEAPOFFSETINTERNAL
+{
+ /** The typical magic (RTHEAPOFFSET_MAGIC). */
+ uint32_t u32Magic;
+ /** The heap size. (This structure is included!) */
+ uint32_t cbHeap;
+ /** The amount of free memory in the heap. */
+ uint32_t cbFree;
+ /** Free head pointer. */
+ uint32_t /*PRTHEAPOFFSETFREE*/ offFreeHead;
+ /** Free tail pointer. */
+ uint32_t /*PRTHEAPOFFSETFREE*/ offFreeTail;
+ /** Make the size of this structure 32 bytes. */
+ uint32_t au32Alignment[3];
+} RTHEAPOFFSETINTERNAL;
+AssertCompileSize(RTHEAPOFFSETINTERNAL, 32);
+
+
+/** The minimum allocation size. */
+#define RTHEAPOFFSET_MIN_BLOCK (sizeof(RTHEAPOFFSETBLOCK))
+AssertCompile(RTHEAPOFFSET_MIN_BLOCK >= sizeof(RTHEAPOFFSETBLOCK));
+AssertCompile(RTHEAPOFFSET_MIN_BLOCK >= sizeof(RTHEAPOFFSETFREE) - sizeof(RTHEAPOFFSETBLOCK));
+
+/** The minimum and default alignment. */
+#define RTHEAPOFFSET_ALIGNMENT (sizeof(RTHEAPOFFSETBLOCK))
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+#ifdef RT_STRICT
+# define RTHEAPOFFSET_STRICT 1
+#endif
+
+/**
+ * Converts RTHEAPOFFSETBLOCK::offSelf into a heap anchor block pointer.
+ *
+ * @returns Pointer of given type.
+ * @param pBlock The block to find the heap anchor block for.
+ */
+#define RTHEAPOFF_GET_ANCHOR(pBlock) ( (PRTHEAPOFFSETINTERNAL)((uint8_t *)(pBlock) - (pBlock)->offSelf ) )
+
+
+/**
+ * Converts an offset to a pointer.
+ *
+ * All offsets are relative to the heap to make life simple.
+ *
+ * @returns Pointer of given type.
+ * @param pHeapInt Pointer to the heap anchor block.
+ * @param off The offset to convert.
+ * @param type The desired type.
+ */
+#ifdef RTHEAPOFFSET_STRICT
+# define RTHEAPOFF_TO_PTR_N(pHeapInt, off, type) ( (type)rtHeapOffCheckedOffToPtr(pHeapInt, off, true /*fNull*/) )
+#else
+# define RTHEAPOFF_TO_PTR_N(pHeapInt, off, type) ( (type)((off) ? (uint8_t *)(pHeapInt) + (off) : NULL) )
+#endif
+
+/**
+ * Converts an offset to a pointer.
+ *
+ * All offsets are relative to the heap to make life simple.
+ *
+ * @returns Pointer of given type.
+ * @param pHeapInt Pointer to the heap anchor block.
+ * @param off The offset to convert.
+ * @param type The desired type.
+ */
+#ifdef RTHEAPOFFSET_STRICT
+# define RTHEAPOFF_TO_PTR(pHeapInt, off, type) ( (type)rtHeapOffCheckedOffToPtr(pHeapInt, off, false /*fNull*/) )
+#else
+# define RTHEAPOFF_TO_PTR(pHeapInt, off, type) ( (type)((uint8_t *)(pHeapInt) + (off)) )
+#endif
+
+/**
+ * Converts a pointer to an offset.
+ *
+ * All offsets are relative to the heap to make life simple.
+ *
+ * @returns Offset into the heap.
+ * @param pHeapInt Pointer to the heap anchor block.
+ * @param ptr The pointer to convert.
+ */
+#ifdef RTHEAPOFFSET_STRICT
+# define RTHEAPOFF_TO_OFF(pHeapInt, ptr) rtHeapOffCheckedPtrToOff(pHeapInt, ptr)
+#else
+# define RTHEAPOFF_TO_OFF(pHeapInt, ptr) ( (uint32_t)((ptr) ? (uintptr_t)(ptr) - (uintptr_t)(pHeapInt) : UINT32_C(0)) )
+#endif
+
+#define ASSERT_L(a, b) AssertMsg((a) < (b), ("a=%08x b=%08x\n", (a), (b)))
+#define ASSERT_LE(a, b) AssertMsg((a) <= (b), ("a=%08x b=%08x\n", (a), (b)))
+#define ASSERT_G(a, b) AssertMsg((a) > (b), ("a=%08x b=%08x\n", (a), (b)))
+#define ASSERT_GE(a, b) AssertMsg((a) >= (b), ("a=%08x b=%08x\n", (a), (b)))
+#define ASSERT_ALIGN(a) AssertMsg(!((uintptr_t)(a) & (RTHEAPOFFSET_ALIGNMENT - 1)), ("a=%p\n", (uintptr_t)(a)))
+
+#define ASSERT_PREV(pHeapInt, pBlock) \
+ do { ASSERT_ALIGN((pBlock)->offPrev); \
+ if ((pBlock)->offPrev) \
+ { \
+ ASSERT_L((pBlock)->offPrev, RTHEAPOFF_TO_OFF(pHeapInt, pBlock)); \
+ ASSERT_GE((pBlock)->offPrev, sizeof(RTHEAPOFFSETINTERNAL)); \
+ } \
+ else \
+ Assert((pBlock) == (PRTHEAPOFFSETBLOCK)((pHeapInt) + 1)); \
+ } while (0)
+
+#define ASSERT_NEXT(pHeap, pBlock) \
+ do { ASSERT_ALIGN((pBlock)->offNext); \
+ if ((pBlock)->offNext) \
+ { \
+ ASSERT_L((pBlock)->offNext, (pHeapInt)->cbHeap); \
+ ASSERT_G((pBlock)->offNext, RTHEAPOFF_TO_OFF(pHeapInt, pBlock)); \
+ } \
+ } while (0)
+
+#define ASSERT_BLOCK(pHeapInt, pBlock) \
+ do { AssertMsg(RTHEAPOFFSETBLOCK_IS_VALID(pBlock), ("%#x\n", (pBlock)->fFlags)); \
+ AssertMsg(RTHEAPOFF_GET_ANCHOR(pBlock) == (pHeapInt), ("%p != %p\n", RTHEAPOFF_GET_ANCHOR(pBlock), (pHeapInt))); \
+ ASSERT_GE(RTHEAPOFF_TO_OFF(pHeapInt, pBlock), sizeof(RTHEAPOFFSETINTERNAL)); \
+ ASSERT_L( RTHEAPOFF_TO_OFF(pHeapInt, pBlock), (pHeapInt)->cbHeap); \
+ ASSERT_NEXT(pHeapInt, pBlock); \
+ ASSERT_PREV(pHeapInt, pBlock); \
+ } while (0)
+
+#define ASSERT_BLOCK_USED(pHeapInt, pBlock) \
+ do { AssertMsg(RTHEAPOFFSETBLOCK_IS_VALID_USED((pBlock)), ("%#x\n", (pBlock)->fFlags)); \
+ AssertMsg(RTHEAPOFF_GET_ANCHOR(pBlock) == (pHeapInt), ("%p != %p\n", RTHEAPOFF_GET_ANCHOR(pBlock), (pHeapInt))); \
+ ASSERT_GE(RTHEAPOFF_TO_OFF(pHeapInt, pBlock), sizeof(RTHEAPOFFSETINTERNAL)); \
+ ASSERT_L( RTHEAPOFF_TO_OFF(pHeapInt, pBlock), (pHeapInt)->cbHeap); \
+ ASSERT_NEXT(pHeapInt, pBlock); \
+ ASSERT_PREV(pHeapInt, pBlock); \
+ } while (0)
+
+#define ASSERT_FREE_PREV(pHeapInt, pBlock) \
+ do { ASSERT_ALIGN((pBlock)->offPrev); \
+ if ((pBlock)->offPrev) \
+ { \
+ ASSERT_GE((pBlock)->offPrev, (pHeapInt)->offFreeHead); \
+ ASSERT_L((pBlock)->offPrev, RTHEAPOFF_TO_OFF(pHeapInt, pBlock)); \
+ ASSERT_LE((pBlock)->offPrev, (pBlock)->Core.offPrev); \
+ } \
+ else \
+ Assert((pBlock) == RTHEAPOFF_TO_PTR(pHeapInt, (pHeapInt)->offFreeHead, PRTHEAPOFFSETFREE) ); \
+ } while (0)
+
+#define ASSERT_FREE_NEXT(pHeapInt, pBlock) \
+ do { ASSERT_ALIGN((pBlock)->offNext); \
+ if ((pBlock)->offNext) \
+ { \
+ ASSERT_LE((pBlock)->offNext, (pHeapInt)->offFreeTail); \
+ ASSERT_G((pBlock)->offNext, RTHEAPOFF_TO_OFF(pHeapInt, pBlock)); \
+ ASSERT_GE((pBlock)->offNext, (pBlock)->Core.offNext); \
+ } \
+ else \
+ Assert((pBlock) == RTHEAPOFF_TO_PTR(pHeapInt, (pHeapInt)->offFreeTail, PRTHEAPOFFSETFREE)); \
+ } while (0)
+
+#ifdef RTHEAPOFFSET_STRICT
+# define ASSERT_FREE_CB(pHeapInt, pBlock) \
+ do { size_t cbCalc = ((pBlock)->Core.offNext ? (pBlock)->Core.offNext : (pHeapInt)->cbHeap) \
+ - RTHEAPOFF_TO_OFF((pHeapInt), (pBlock)) - sizeof(RTHEAPOFFSETBLOCK); \
+ AssertMsg((pBlock)->cb == cbCalc, ("cb=%#zx cbCalc=%#zx\n", (pBlock)->cb, cbCalc)); \
+ } while (0)
+#else
+# define ASSERT_FREE_CB(pHeapInt, pBlock) do {} while (0)
+#endif
+
+/** Asserts that a free block is valid. */
+#define ASSERT_BLOCK_FREE(pHeapInt, pBlock) \
+ do { ASSERT_BLOCK(pHeapInt, &(pBlock)->Core); \
+ Assert(RTHEAPOFFSETBLOCK_IS_VALID_FREE(&(pBlock)->Core)); \
+ ASSERT_GE(RTHEAPOFF_TO_OFF(pHeapInt, pBlock), (pHeapInt)->offFreeHead); \
+ ASSERT_LE(RTHEAPOFF_TO_OFF(pHeapInt, pBlock), (pHeapInt)->offFreeTail); \
+ ASSERT_FREE_NEXT(pHeapInt, pBlock); \
+ ASSERT_FREE_PREV(pHeapInt, pBlock); \
+ ASSERT_FREE_CB(pHeapInt, pBlock); \
+ } while (0)
+
+/** Asserts that the heap anchor block is ok. */
+#define ASSERT_ANCHOR(pHeapInt) \
+ do { AssertPtr(pHeapInt);\
+ Assert((pHeapInt)->u32Magic == RTHEAPOFFSET_MAGIC); \
+ } while (0)
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+#ifdef RTHEAPOFFSET_STRICT
+static void rtHeapOffsetAssertAll(PRTHEAPOFFSETINTERNAL pHeapInt);
+#endif
+static PRTHEAPOFFSETBLOCK rtHeapOffsetAllocBlock(PRTHEAPOFFSETINTERNAL pHeapInt, size_t cb, size_t uAlignment);
+static void rtHeapOffsetFreeBlock(PRTHEAPOFFSETINTERNAL pHeapInt, PRTHEAPOFFSETBLOCK pBlock);
+
+#ifdef RTHEAPOFFSET_STRICT
+
+/** Checked version of RTHEAPOFF_TO_PTR and RTHEAPOFF_TO_PTR_N. */
+static void *rtHeapOffCheckedOffToPtr(PRTHEAPOFFSETINTERNAL pHeapInt, uint32_t off, bool fNull)
+{
+ Assert(off || fNull);
+ if (!off)
+ return NULL;
+ AssertMsg(off < pHeapInt->cbHeap, ("%#x %#x\n", off, pHeapInt->cbHeap));
+ AssertMsg(off >= sizeof(*pHeapInt), ("%#x %#x\n", off, sizeof(*pHeapInt)));
+ return (uint8_t *)pHeapInt + off;
+}
+
+/** Checked version of RTHEAPOFF_TO_OFF. */
+static uint32_t rtHeapOffCheckedPtrToOff(PRTHEAPOFFSETINTERNAL pHeapInt, void *pv)
+{
+ if (!pv)
+ return 0;
+ uintptr_t off = (uintptr_t)pv - (uintptr_t)pHeapInt;
+ AssertMsg(off < pHeapInt->cbHeap, ("%#x %#x\n", off, pHeapInt->cbHeap));
+ AssertMsg(off >= sizeof(*pHeapInt), ("%#x %#x\n", off, sizeof(*pHeapInt)));
+ return (uint32_t)off;
+}
+
+#endif /* RTHEAPOFFSET_STRICT */
+
+
+
+RTDECL(int) RTHeapOffsetInit(PRTHEAPOFFSET phHeap, void *pvMemory, size_t cbMemory)
+{
+ PRTHEAPOFFSETINTERNAL pHeapInt;
+ PRTHEAPOFFSETFREE pFree;
+ unsigned i;
+
+ /*
+ * Validate input. The imposed minimum heap size is just a convenient value.
+ */
+ AssertReturn(cbMemory >= PAGE_SIZE, VERR_INVALID_PARAMETER);
+ AssertReturn(cbMemory < UINT32_MAX, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pvMemory, VERR_INVALID_POINTER);
+ AssertReturn((uintptr_t)pvMemory + (cbMemory - 1) > (uintptr_t)cbMemory, VERR_INVALID_PARAMETER);
+
+ /*
+ * Place the heap anchor block at the start of the heap memory,
+ * enforce 32 byte alignment of it. Also align the heap size correctly.
+ */
+ pHeapInt = (PRTHEAPOFFSETINTERNAL)pvMemory;
+ if ((uintptr_t)pvMemory & 31)
+ {
+ const uintptr_t off = 32 - ((uintptr_t)pvMemory & 31);
+ cbMemory -= off;
+ pHeapInt = (PRTHEAPOFFSETINTERNAL)((uintptr_t)pvMemory + off);
+ }
+ cbMemory &= ~(RTHEAPOFFSET_ALIGNMENT - 1);
+
+
+ /* Init the heap anchor block. */
+ pHeapInt->u32Magic = RTHEAPOFFSET_MAGIC;
+ pHeapInt->cbHeap = (uint32_t)cbMemory;
+ pHeapInt->cbFree = (uint32_t)cbMemory
+ - sizeof(RTHEAPOFFSETBLOCK)
+ - sizeof(RTHEAPOFFSETINTERNAL);
+ pHeapInt->offFreeTail = pHeapInt->offFreeHead = sizeof(*pHeapInt);
+ for (i = 0; i < RT_ELEMENTS(pHeapInt->au32Alignment); i++)
+ pHeapInt->au32Alignment[i] = UINT32_MAX;
+
+ /* Init the single free block. */
+ pFree = RTHEAPOFF_TO_PTR(pHeapInt, pHeapInt->offFreeHead, PRTHEAPOFFSETFREE);
+ pFree->Core.offNext = 0;
+ pFree->Core.offPrev = 0;
+ pFree->Core.offSelf = pHeapInt->offFreeHead;
+ pFree->Core.fFlags = RTHEAPOFFSETBLOCK_FLAGS_MAGIC | RTHEAPOFFSETBLOCK_FLAGS_FREE;
+ pFree->offNext = 0;
+ pFree->offPrev = 0;
+ pFree->cb = pHeapInt->cbFree;
+
+ *phHeap = pHeapInt;
+
+#ifdef RTHEAPOFFSET_STRICT
+ rtHeapOffsetAssertAll(pHeapInt);
+#endif
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTHeapOffsetInit);
+
+
+RTDECL(void *) RTHeapOffsetAlloc(RTHEAPOFFSET hHeap, size_t cb, size_t cbAlignment)
+{
+ PRTHEAPOFFSETINTERNAL pHeapInt = hHeap;
+ PRTHEAPOFFSETBLOCK pBlock;
+
+ /*
+ * Validate and adjust the input.
+ */
+ AssertPtrReturn(pHeapInt, NULL);
+ if (cb < RTHEAPOFFSET_MIN_BLOCK)
+ cb = RTHEAPOFFSET_MIN_BLOCK;
+ else
+ cb = RT_ALIGN_Z(cb, RTHEAPOFFSET_ALIGNMENT);
+ if (!cbAlignment)
+ cbAlignment = RTHEAPOFFSET_ALIGNMENT;
+ else
+ {
+ Assert(!(cbAlignment & (cbAlignment - 1)));
+ Assert((cbAlignment & ~(cbAlignment - 1)) == cbAlignment);
+ if (cbAlignment < RTHEAPOFFSET_ALIGNMENT)
+ cbAlignment = RTHEAPOFFSET_ALIGNMENT;
+ }
+
+ /*
+ * Do the allocation.
+ */
+ pBlock = rtHeapOffsetAllocBlock(pHeapInt, cb, cbAlignment);
+ if (RT_LIKELY(pBlock))
+ {
+ void *pv = pBlock + 1;
+ return pv;
+ }
+ return NULL;
+}
+RT_EXPORT_SYMBOL(RTHeapOffsetAlloc);
+
+
+RTDECL(void *) RTHeapOffsetAllocZ(RTHEAPOFFSET hHeap, size_t cb, size_t cbAlignment)
+{
+ PRTHEAPOFFSETINTERNAL pHeapInt = hHeap;
+ PRTHEAPOFFSETBLOCK pBlock;
+
+ /*
+ * Validate and adjust the input.
+ */
+ AssertPtrReturn(pHeapInt, NULL);
+ if (cb < RTHEAPOFFSET_MIN_BLOCK)
+ cb = RTHEAPOFFSET_MIN_BLOCK;
+ else
+ cb = RT_ALIGN_Z(cb, RTHEAPOFFSET_ALIGNMENT);
+ if (!cbAlignment)
+ cbAlignment = RTHEAPOFFSET_ALIGNMENT;
+ else
+ {
+ Assert(!(cbAlignment & (cbAlignment - 1)));
+ Assert((cbAlignment & ~(cbAlignment - 1)) == cbAlignment);
+ if (cbAlignment < RTHEAPOFFSET_ALIGNMENT)
+ cbAlignment = RTHEAPOFFSET_ALIGNMENT;
+ }
+
+ /*
+ * Do the allocation.
+ */
+ pBlock = rtHeapOffsetAllocBlock(pHeapInt, cb, cbAlignment);
+ if (RT_LIKELY(pBlock))
+ {
+ void *pv = pBlock + 1;
+ memset(pv, 0, cb);
+ return pv;
+ }
+ return NULL;
+}
+RT_EXPORT_SYMBOL(RTHeapOffsetAllocZ);
+
+
+/**
+ * Allocates a block of memory from the specified heap.
+ *
+ * No parameter validation or adjustment is performed.
+ *
+ * @returns Pointer to the allocated block.
+ * @returns NULL on failure.
+ *
+ * @param pHeapInt The heap.
+ * @param cb Size of the memory block to allocate.
+ * @param uAlignment The alignment specifications for the allocated block.
+ */
+static PRTHEAPOFFSETBLOCK rtHeapOffsetAllocBlock(PRTHEAPOFFSETINTERNAL pHeapInt, size_t cb, size_t uAlignment)
+{
+ PRTHEAPOFFSETBLOCK pRet = NULL;
+ PRTHEAPOFFSETFREE pFree;
+
+ AssertReturn((pHeapInt)->u32Magic == RTHEAPOFFSET_MAGIC, NULL);
+#ifdef RTHEAPOFFSET_STRICT
+ rtHeapOffsetAssertAll(pHeapInt);
+#endif
+
+ /*
+ * Search for a fitting block from the lower end of the heap.
+ */
+ for (pFree = RTHEAPOFF_TO_PTR_N(pHeapInt, pHeapInt->offFreeHead, PRTHEAPOFFSETFREE);
+ pFree;
+ pFree = RTHEAPOFF_TO_PTR_N(pHeapInt, pFree->offNext, PRTHEAPOFFSETFREE))
+ {
+ uintptr_t offAlign;
+ ASSERT_BLOCK_FREE(pHeapInt, pFree);
+
+ /*
+ * Match for size and alignment.
+ */
+ if (pFree->cb < cb)
+ continue;
+ offAlign = (uintptr_t)(&pFree->Core + 1) & (uAlignment - 1);
+ if (offAlign)
+ {
+ PRTHEAPOFFSETFREE pPrev;
+
+ offAlign = (uintptr_t)(&pFree[1].Core + 1) & (uAlignment - 1);
+ offAlign = uAlignment - offAlign;
+ if (pFree->cb < cb + offAlign + sizeof(RTHEAPOFFSETFREE))
+ continue;
+
+ /*
+ * Split up the free block into two, so that the 2nd is aligned as
+ * per specification.
+ */
+ pPrev = pFree;
+ pFree = (PRTHEAPOFFSETFREE)((uintptr_t)(pFree + 1) + offAlign);
+ pFree->Core.offPrev = pPrev->Core.offSelf;
+ pFree->Core.offNext = pPrev->Core.offNext;
+ pFree->Core.offSelf = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
+ pFree->Core.fFlags = RTHEAPOFFSETBLOCK_FLAGS_MAGIC | RTHEAPOFFSETBLOCK_FLAGS_FREE;
+ pFree->offPrev = pPrev->Core.offSelf;
+ pFree->offNext = pPrev->offNext;
+ pFree->cb = (pFree->Core.offNext ? pFree->Core.offNext : pHeapInt->cbHeap)
+ - pFree->Core.offSelf - sizeof(RTHEAPOFFSETBLOCK);
+
+ pPrev->Core.offNext = pFree->Core.offSelf;
+ pPrev->offNext = pFree->Core.offSelf;
+ pPrev->cb = pFree->Core.offSelf - pPrev->Core.offSelf - sizeof(RTHEAPOFFSETBLOCK);
+
+ if (pFree->Core.offNext)
+ RTHEAPOFF_TO_PTR(pHeapInt, pFree->Core.offNext, PRTHEAPOFFSETBLOCK)->offPrev = pFree->Core.offSelf;
+ if (pFree->offNext)
+ RTHEAPOFF_TO_PTR(pHeapInt, pFree->Core.offNext, PRTHEAPOFFSETFREE)->offPrev = pFree->Core.offSelf;
+ else
+ pHeapInt->offFreeTail = pFree->Core.offSelf;
+
+ pHeapInt->cbFree -= sizeof(RTHEAPOFFSETBLOCK);
+ ASSERT_BLOCK_FREE(pHeapInt, pPrev);
+ ASSERT_BLOCK_FREE(pHeapInt, pFree);
+ }
+
+ /*
+ * Split off a new FREE block?
+ */
+ if (pFree->cb >= cb + RT_ALIGN_Z(sizeof(RTHEAPOFFSETFREE), RTHEAPOFFSET_ALIGNMENT))
+ {
+ /*
+ * Create a new FREE block at then end of this one.
+ */
+ PRTHEAPOFFSETFREE pNew = (PRTHEAPOFFSETFREE)((uintptr_t)&pFree->Core + cb + sizeof(RTHEAPOFFSETBLOCK));
+
+ pNew->Core.offSelf = RTHEAPOFF_TO_OFF(pHeapInt, pNew);
+ pNew->Core.offNext = pFree->Core.offNext;
+ if (pFree->Core.offNext)
+ RTHEAPOFF_TO_PTR(pHeapInt, pFree->Core.offNext, PRTHEAPOFFSETBLOCK)->offPrev = pNew->Core.offSelf;
+ pNew->Core.offPrev = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
+ pNew->Core.fFlags = RTHEAPOFFSETBLOCK_FLAGS_MAGIC | RTHEAPOFFSETBLOCK_FLAGS_FREE;
+
+ pNew->offNext = pFree->offNext;
+ if (pNew->offNext)
+ RTHEAPOFF_TO_PTR(pHeapInt, pNew->offNext, PRTHEAPOFFSETFREE)->offPrev = pNew->Core.offSelf;
+ else
+ pHeapInt->offFreeTail = pNew->Core.offSelf;
+ pNew->offPrev = pFree->offPrev;
+ if (pNew->offPrev)
+ RTHEAPOFF_TO_PTR(pHeapInt, pNew->offPrev, PRTHEAPOFFSETFREE)->offNext = pNew->Core.offSelf;
+ else
+ pHeapInt->offFreeHead = pNew->Core.offSelf;
+ pNew->cb = (pNew->Core.offNext ? pNew->Core.offNext : pHeapInt->cbHeap) \
+ - pNew->Core.offSelf - sizeof(RTHEAPOFFSETBLOCK);
+ ASSERT_BLOCK_FREE(pHeapInt, pNew);
+
+ /*
+ * Adjust and convert the old FREE node into a USED node.
+ */
+ pFree->Core.fFlags &= ~RTHEAPOFFSETBLOCK_FLAGS_FREE;
+ pFree->Core.offNext = pNew->Core.offSelf;
+ pHeapInt->cbFree -= pFree->cb;
+ pHeapInt->cbFree += pNew->cb;
+ pRet = &pFree->Core;
+ ASSERT_BLOCK_USED(pHeapInt, pRet);
+ }
+ else
+ {
+ /*
+ * Link it out of the free list.
+ */
+ if (pFree->offNext)
+ RTHEAPOFF_TO_PTR(pHeapInt, pFree->offNext, PRTHEAPOFFSETFREE)->offPrev = pFree->offPrev;
+ else
+ pHeapInt->offFreeTail = pFree->offPrev;
+ if (pFree->offPrev)
+ RTHEAPOFF_TO_PTR(pHeapInt, pFree->offPrev, PRTHEAPOFFSETFREE)->offNext = pFree->offNext;
+ else
+ pHeapInt->offFreeHead = pFree->offNext;
+
+ /*
+ * Convert it to a used block.
+ */
+ pHeapInt->cbFree -= pFree->cb;
+ pFree->Core.fFlags &= ~RTHEAPOFFSETBLOCK_FLAGS_FREE;
+ pRet = &pFree->Core;
+ ASSERT_BLOCK_USED(pHeapInt, pRet);
+ }
+ break;
+ }
+
+#ifdef RTHEAPOFFSET_STRICT
+ rtHeapOffsetAssertAll(pHeapInt);
+#endif
+ return pRet;
+}
+
+
+RTDECL(void) RTHeapOffsetFree(RTHEAPOFFSET hHeap, void *pv)
+{
+ PRTHEAPOFFSETINTERNAL pHeapInt;
+ PRTHEAPOFFSETBLOCK pBlock;
+
+ /*
+ * Validate input.
+ */
+ if (!pv)
+ return;
+ AssertPtr(pv);
+ Assert(RT_ALIGN_P(pv, RTHEAPOFFSET_ALIGNMENT) == pv);
+
+ /*
+ * Get the block and heap. If in strict mode, validate these.
+ */
+ pBlock = (PRTHEAPOFFSETBLOCK)pv - 1;
+ pHeapInt = RTHEAPOFF_GET_ANCHOR(pBlock);
+ ASSERT_BLOCK_USED(pHeapInt, pBlock);
+ ASSERT_ANCHOR(pHeapInt);
+ Assert(pHeapInt == (PRTHEAPOFFSETINTERNAL)hHeap || !hHeap); RT_NOREF_PV(hHeap);
+
+#ifdef RTHEAPOFFSET_FREE_POISON
+ /*
+ * Poison the block.
+ */
+ const size_t cbBlock = (pBlock->pNext ? (uintptr_t)pBlock->pNext : (uintptr_t)pHeapInt->pvEnd)
+ - (uintptr_t)pBlock - sizeof(RTHEAPOFFSETBLOCK);
+ memset(pBlock + 1, RTHEAPOFFSET_FREE_POISON, cbBlock);
+#endif
+
+ /*
+ * Call worker which does the actual job.
+ */
+ rtHeapOffsetFreeBlock(pHeapInt, pBlock);
+}
+RT_EXPORT_SYMBOL(RTHeapOffsetFree);
+
+
+/**
+ * Free a memory block.
+ *
+ * @param pHeapInt The heap.
+ * @param pBlock The memory block to free.
+ */
+static void rtHeapOffsetFreeBlock(PRTHEAPOFFSETINTERNAL pHeapInt, PRTHEAPOFFSETBLOCK pBlock)
+{
+ PRTHEAPOFFSETFREE pFree = (PRTHEAPOFFSETFREE)pBlock;
+ PRTHEAPOFFSETFREE pLeft;
+ PRTHEAPOFFSETFREE pRight;
+
+#ifdef RTHEAPOFFSET_STRICT
+ rtHeapOffsetAssertAll(pHeapInt);
+#endif
+
+ /*
+ * Look for the closest free list blocks by walking the blocks right
+ * of us (both lists are sorted by address).
+ */
+ pLeft = NULL;
+ pRight = NULL;
+ if (pHeapInt->offFreeTail)
+ {
+ pRight = RTHEAPOFF_TO_PTR_N(pHeapInt, pFree->Core.offNext, PRTHEAPOFFSETFREE);
+ while (pRight && !RTHEAPOFFSETBLOCK_IS_FREE(&pRight->Core))
+ {
+ ASSERT_BLOCK(pHeapInt, &pRight->Core);
+ pRight = RTHEAPOFF_TO_PTR_N(pHeapInt, pRight->Core.offNext, PRTHEAPOFFSETFREE);
+ }
+ if (!pRight)
+ pLeft = RTHEAPOFF_TO_PTR_N(pHeapInt, pHeapInt->offFreeTail, PRTHEAPOFFSETFREE);
+ else
+ {
+ ASSERT_BLOCK_FREE(pHeapInt, pRight);
+ pLeft = RTHEAPOFF_TO_PTR_N(pHeapInt, pRight->offPrev, PRTHEAPOFFSETFREE);
+ }
+ if (pLeft)
+ ASSERT_BLOCK_FREE(pHeapInt, pLeft);
+ }
+ AssertMsgReturnVoid(pLeft != pFree, ("Freed twice! pv=%p (pBlock=%p)\n", pBlock + 1, pBlock));
+ ASSERT_L(RTHEAPOFF_TO_OFF(pHeapInt, pLeft), RTHEAPOFF_TO_OFF(pHeapInt, pFree));
+ Assert(!pRight || (uintptr_t)pRight > (uintptr_t)pFree);
+ Assert(!pLeft || RTHEAPOFF_TO_PTR_N(pHeapInt, pLeft->offNext, PRTHEAPOFFSETFREE) == pRight);
+
+ /*
+ * Insert at the head of the free block list?
+ */
+ if (!pLeft)
+ {
+ Assert(pRight == RTHEAPOFF_TO_PTR_N(pHeapInt, pHeapInt->offFreeHead, PRTHEAPOFFSETFREE));
+ pFree->Core.fFlags |= RTHEAPOFFSETBLOCK_FLAGS_FREE;
+ pFree->offPrev = 0;
+ pFree->offNext = RTHEAPOFF_TO_OFF(pHeapInt, pRight);
+ if (pRight)
+ pRight->offPrev = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
+ else
+ pHeapInt->offFreeTail = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
+ pHeapInt->offFreeHead = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
+ }
+ else
+ {
+ /*
+ * Can we merge with left hand free block?
+ */
+ if (pLeft->Core.offNext == RTHEAPOFF_TO_OFF(pHeapInt, pFree))
+ {
+ pLeft->Core.offNext = pFree->Core.offNext;
+ if (pFree->Core.offNext)
+ RTHEAPOFF_TO_PTR(pHeapInt, pFree->Core.offNext, PRTHEAPOFFSETBLOCK)->offPrev = RTHEAPOFF_TO_OFF(pHeapInt, pLeft);
+ pHeapInt->cbFree -= pLeft->cb;
+ pFree = pLeft;
+ }
+ /*
+ * No, just link it into the free list then.
+ */
+ else
+ {
+ pFree->Core.fFlags |= RTHEAPOFFSETBLOCK_FLAGS_FREE;
+ pFree->offNext = RTHEAPOFF_TO_OFF(pHeapInt, pRight);
+ pFree->offPrev = RTHEAPOFF_TO_OFF(pHeapInt, pLeft);
+ pLeft->offNext = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
+ if (pRight)
+ pRight->offPrev = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
+ else
+ pHeapInt->offFreeTail = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
+ }
+ }
+
+ /*
+ * Can we merge with right hand free block?
+ */
+ if ( pRight
+ && pRight->Core.offPrev == RTHEAPOFF_TO_OFF(pHeapInt, pFree))
+ {
+ /* core */
+ pFree->Core.offNext = pRight->Core.offNext;
+ if (pRight->Core.offNext)
+ RTHEAPOFF_TO_PTR(pHeapInt, pRight->Core.offNext, PRTHEAPOFFSETBLOCK)->offPrev = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
+
+ /* free */
+ pFree->offNext = pRight->offNext;
+ if (pRight->offNext)
+ RTHEAPOFF_TO_PTR(pHeapInt, pRight->offNext, PRTHEAPOFFSETFREE)->offPrev = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
+ else
+ pHeapInt->offFreeTail = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
+ pHeapInt->cbFree -= pRight->cb;
+ }
+
+ /*
+ * Calculate the size and update free stats.
+ */
+ pFree->cb = (pFree->Core.offNext ? pFree->Core.offNext : pHeapInt->cbHeap)
+ - RTHEAPOFF_TO_OFF(pHeapInt, pFree) - sizeof(RTHEAPOFFSETBLOCK);
+ pHeapInt->cbFree += pFree->cb;
+ ASSERT_BLOCK_FREE(pHeapInt, pFree);
+
+#ifdef RTHEAPOFFSET_STRICT
+ rtHeapOffsetAssertAll(pHeapInt);
+#endif
+}
+
+
+#ifdef RTHEAPOFFSET_STRICT
+/**
+ * Internal consistency check (relying on assertions).
+ * @param pHeapInt
+ */
+static void rtHeapOffsetAssertAll(PRTHEAPOFFSETINTERNAL pHeapInt)
+{
+ PRTHEAPOFFSETFREE pPrev = NULL;
+ PRTHEAPOFFSETFREE pPrevFree = NULL;
+ PRTHEAPOFFSETFREE pBlock;
+ for (pBlock = (PRTHEAPOFFSETFREE)(pHeapInt + 1);
+ pBlock;
+ pBlock = RTHEAPOFF_TO_PTR_N(pHeapInt, pBlock->Core.offNext, PRTHEAPOFFSETFREE))
+ {
+ if (RTHEAPOFFSETBLOCK_IS_FREE(&pBlock->Core))
+ {
+ ASSERT_BLOCK_FREE(pHeapInt, pBlock);
+ Assert(pBlock->offPrev == RTHEAPOFF_TO_OFF(pHeapInt, pPrevFree));
+ Assert(pPrevFree || pHeapInt->offFreeHead == RTHEAPOFF_TO_OFF(pHeapInt, pBlock));
+ pPrevFree = pBlock;
+ }
+ else
+ ASSERT_BLOCK_USED(pHeapInt, &pBlock->Core);
+ Assert(!pPrev || RTHEAPOFF_TO_OFF(pHeapInt, pPrev) == pBlock->Core.offPrev);
+ pPrev = pBlock;
+ }
+ Assert(pHeapInt->offFreeTail == RTHEAPOFF_TO_OFF(pHeapInt, pPrevFree));
+}
+#endif
+
+
+RTDECL(size_t) RTHeapOffsetSize(RTHEAPOFFSET hHeap, void *pv)
+{
+ PRTHEAPOFFSETINTERNAL pHeapInt;
+ PRTHEAPOFFSETBLOCK pBlock;
+ size_t cbBlock;
+
+ /*
+ * Validate input.
+ */
+ if (!pv)
+ return 0;
+ AssertPtrReturn(pv, 0);
+ AssertReturn(RT_ALIGN_P(pv, RTHEAPOFFSET_ALIGNMENT) == pv, 0);
+
+ /*
+ * Get the block and heap. If in strict mode, validate these.
+ */
+ pBlock = (PRTHEAPOFFSETBLOCK)pv - 1;
+ pHeapInt = RTHEAPOFF_GET_ANCHOR(pBlock);
+ ASSERT_BLOCK_USED(pHeapInt, pBlock);
+ ASSERT_ANCHOR(pHeapInt);
+ Assert(pHeapInt == (PRTHEAPOFFSETINTERNAL)hHeap || !hHeap); RT_NOREF_PV(hHeap);
+
+ /*
+ * Calculate the block size.
+ */
+ cbBlock = (pBlock->offNext ? pBlock->offNext : pHeapInt->cbHeap)
+ - RTHEAPOFF_TO_OFF(pHeapInt, pBlock) - sizeof(RTHEAPOFFSETBLOCK);
+ return cbBlock;
+}
+RT_EXPORT_SYMBOL(RTHeapOffsetSize);
+
+
+RTDECL(size_t) RTHeapOffsetGetHeapSize(RTHEAPOFFSET hHeap)
+{
+ PRTHEAPOFFSETINTERNAL pHeapInt;
+
+ if (hHeap == NIL_RTHEAPOFFSET)
+ return 0;
+
+ pHeapInt = hHeap;
+ AssertPtrReturn(pHeapInt, 0);
+ ASSERT_ANCHOR(pHeapInt);
+ return pHeapInt->cbHeap;
+}
+RT_EXPORT_SYMBOL(RTHeapOffsetGetHeapSize);
+
+
+RTDECL(size_t) RTHeapOffsetGetFreeSize(RTHEAPOFFSET hHeap)
+{
+ PRTHEAPOFFSETINTERNAL pHeapInt;
+
+ if (hHeap == NIL_RTHEAPOFFSET)
+ return 0;
+
+ pHeapInt = hHeap;
+ AssertPtrReturn(pHeapInt, 0);
+ ASSERT_ANCHOR(pHeapInt);
+ return pHeapInt->cbFree;
+}
+RT_EXPORT_SYMBOL(RTHeapOffsetGetFreeSize);
+
+
+RTDECL(void) RTHeapOffsetDump(RTHEAPOFFSET hHeap, PFNRTHEAPOFFSETPRINTF pfnPrintf)
+{
+ PRTHEAPOFFSETINTERNAL pHeapInt = (PRTHEAPOFFSETINTERNAL)hHeap;
+ PRTHEAPOFFSETFREE pBlock;
+
+ pfnPrintf("**** Dumping Heap %p - cbHeap=%x cbFree=%x ****\n",
+ hHeap, pHeapInt->cbHeap, pHeapInt->cbFree);
+
+ for (pBlock = (PRTHEAPOFFSETFREE)(pHeapInt + 1);
+ pBlock;
+ pBlock = RTHEAPOFF_TO_PTR_N(pHeapInt, pBlock->Core.offNext, PRTHEAPOFFSETFREE))
+ {
+ size_t cb = (pBlock->offNext ? pBlock->Core.offNext : pHeapInt->cbHeap)
+ - RTHEAPOFF_TO_OFF(pHeapInt, pBlock) - sizeof(RTHEAPOFFSETBLOCK);
+ if (RTHEAPOFFSETBLOCK_IS_FREE(&pBlock->Core))
+ pfnPrintf("%p %06x FREE offNext=%06x offPrev=%06x fFlags=%#x cb=%#06x : cb=%#06x offNext=%06x offPrev=%06x\n",
+ pBlock, pBlock->Core.offSelf, pBlock->Core.offNext, pBlock->Core.offPrev, pBlock->Core.fFlags, cb,
+ pBlock->cb, pBlock->offNext, pBlock->offPrev);
+ else
+ pfnPrintf("%p %06x USED offNext=%06x offPrev=%06x fFlags=%#x cb=%#06x\n",
+ pBlock, pBlock->Core.offSelf, pBlock->Core.offNext, pBlock->Core.offPrev, pBlock->Core.fFlags, cb);
+ }
+ pfnPrintf("**** Done dumping Heap %p ****\n", hHeap);
+}
+RT_EXPORT_SYMBOL(RTHeapOffsetDump);
+
--- /dev/null
+../include
\ No newline at end of file
--- /dev/null
+#ifndef ___product_generated_h___
+#define ___product_generated_h___
+
+#define VBOX_VENDOR "Oracle Corporation"
+#define VBOX_VENDOR_SHORT "Oracle"
+#define VBOX_PRODUCT "Oracle VM VirtualBox"
+#define VBOX_BUILD_PUBLISHER "_Ubuntu"
+#define VBOX_C_YEAR "2017"
+
+#endif
--- /dev/null
+../r0drv
\ No newline at end of file
--- /dev/null
+#define VBOX_SVN_REV 117968
--- /dev/null
+/* $Id: vbox_drv.c $ */
+/** @file
+ * VirtualBox Additions Linux kernel video driver
+ */
+
+/*
+ * Copyright (C) 2013-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on
+ * ast_drv.c
+ * with the following copyright and permission notice:
+ *
+ * Copyright 2012 Red Hat Inc.
+ *
+ * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors: Dave Airlie <airlied@redhat.com>
+ */
+#include "vbox_drv.h"
+
+#include <VBox/VBoxGuest.h>
+#include "version-generated.h"
+#include "revision-generated.h"
+
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/vt_kern.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+
+int vbox_modeset = -1;
+
+MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
+module_param_named(modeset, vbox_modeset, int, 0400);
+
+static struct drm_driver driver;
+
+static const struct pci_device_id pciidlist[] =
+{
+ {0x80ee, 0xbeef, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0, 0, 0},
+};
+
+MODULE_DEVICE_TABLE(pci, pciidlist);
+
+static int vbox_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ return drm_get_pci_dev(pdev, ent, &driver);
+}
+
+
+static void vbox_pci_remove(struct pci_dev *pdev)
+{
+ struct drm_device *dev = pci_get_drvdata(pdev);
+
+ drm_put_dev(dev);
+}
+
+
+
+static int vbox_drm_freeze(struct drm_device *dev)
+{
+ drm_kms_helper_poll_disable(dev);
+
+ pci_save_state(dev->pdev);
+
+ console_lock();
+ vbox_fbdev_set_suspend(dev, 1);
+ console_unlock();
+ return 0;
+}
+
+static int vbox_drm_thaw(struct drm_device *dev)
+{
+ int error = 0;
+
+ drm_mode_config_reset(dev);
+ drm_helper_resume_force_mode(dev);
+
+ console_lock();
+ vbox_fbdev_set_suspend(dev, 0);
+ console_unlock();
+ return error;
+}
+
+static int vbox_drm_resume(struct drm_device *dev)
+{
+ int ret;
+
+ if (pci_enable_device(dev->pdev))
+ return -EIO;
+
+ ret = vbox_drm_thaw(dev);
+ if (ret)
+ return ret;
+
+ drm_kms_helper_poll_enable(dev);
+ return 0;
+}
+
+static int vbox_pm_suspend(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct drm_device *ddev = pci_get_drvdata(pdev);
+ int error;
+
+ error = vbox_drm_freeze(ddev);
+ if (error)
+ return error;
+
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, PCI_D3hot);
+ return 0;
+}
+
+static int vbox_pm_resume(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct drm_device *ddev = pci_get_drvdata(pdev);
+ return vbox_drm_resume(ddev);
+}
+
+static int vbox_pm_freeze(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct drm_device *ddev = pci_get_drvdata(pdev);
+
+ if (!ddev || !ddev->dev_private)
+ return -ENODEV;
+ return vbox_drm_freeze(ddev);
+
+}
+
+static int vbox_pm_thaw(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct drm_device *ddev = pci_get_drvdata(pdev);
+ return vbox_drm_thaw(ddev);
+}
+
+static int vbox_pm_poweroff(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct drm_device *ddev = pci_get_drvdata(pdev);
+
+ return vbox_drm_freeze(ddev);
+}
+
+static const struct dev_pm_ops vbox_pm_ops = {
+ .suspend = vbox_pm_suspend,
+ .resume = vbox_pm_resume,
+ .freeze = vbox_pm_freeze,
+ .thaw = vbox_pm_thaw,
+ .poweroff = vbox_pm_poweroff,
+ .restore = vbox_pm_resume,
+};
+
+static struct pci_driver vbox_pci_driver =
+{
+ .name = DRIVER_NAME,
+ .id_table = pciidlist,
+ .probe = vbox_pci_probe,
+ .remove = vbox_pci_remove,
+ .driver.pm = &vbox_pm_ops,
+};
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) && !defined(RHEL_74)
+/* This works around a bug in X servers prior to 1.18.4, which sometimes
+ * submit more dirty rectangles than the kernel is willing to handle and
+ * then disable dirty rectangle handling altogether when they see the
+ * EINVAL error. I do not want the code to hang around forever, which is
+ * why I am limiting it to certain kernel versions. We can increase the
+ * limit if some distributions uses old X servers with new kernels. */
+long vbox_ioctl(struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ long rc = drm_ioctl(filp, cmd, arg);
+ if (cmd == DRM_IOCTL_MODE_DIRTYFB && rc == -EINVAL)
+ return -EOVERFLOW;
+ return rc;
+}
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) && !RHEL_74 */
+
+static const struct file_operations vbox_fops =
+{
+ .owner = THIS_MODULE,
+ .open = drm_open,
+ .release = drm_release,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) && !defined(RHEL_74)
+ .unlocked_ioctl = vbox_ioctl,
+#else
+ .unlocked_ioctl = drm_ioctl,
+#endif
+ .mmap = vbox_mmap,
+ .poll = drm_poll,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0) && !defined(RHEL_73)
+ .fasync = drm_fasync,
+#endif
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = drm_compat_ioctl,
+#endif
+ .read = drm_read,
+};
+
+static int vbox_master_set(struct drm_device *dev,
+ struct drm_file *file_priv,
+ bool from_open)
+{
+ struct vbox_private *vbox = dev->dev_private;
+ /* We do not yet know whether the new owner can handle hotplug, so we
+ * do not advertise dynamic modes on the first query and send a
+ * tentative hotplug notification after that to see if they query again. */
+ vbox->initial_mode_queried = false;
+ mutex_lock(&vbox->hw_mutex);
+ /* Disable VBVA when someone releases master in case the next person tries
+ * to do VESA. */
+ /** @todo work out if anyone is likely to and whether it will even work. */
+ /* Update: we also disable it because if the new master does not do dirty
+ * rectangle reporting (e.g. old versions of Plymouth) then at least the
+ * first screen will still be updated. We enable it as soon as we
+ * receive a dirty rectangle report. */
+ vbox_disable_accel(vbox);
+ mutex_unlock(&vbox->hw_mutex);
+ return 0;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0) && !defined(RHEL_74)
+static void vbox_master_drop(struct drm_device *dev,
+ struct drm_file *file_priv,
+ bool from_release)
+#else
+static void vbox_master_drop(struct drm_device *dev,
+ struct drm_file *file_priv)
+#endif
+{
+ struct vbox_private *vbox = dev->dev_private;
+ /* See vbox_master_set() */
+ vbox->initial_mode_queried = false;
+ mutex_lock(&vbox->hw_mutex);
+ vbox_disable_accel(vbox);
+ mutex_unlock(&vbox->hw_mutex);
+}
+
+static struct drm_driver driver =
+{
+ .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_PRIME,
+ .dev_priv_size = 0,
+
+ .load = vbox_driver_load,
+ .unload = vbox_driver_unload,
+ .lastclose = vbox_driver_lastclose,
+ .master_set = vbox_master_set,
+ .master_drop = vbox_master_drop,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0) || defined(RHEL_73)
+ .set_busid = drm_pci_set_busid,
+#endif
+
+ .fops = &vbox_fops,
+ .irq_handler = vbox_irq_handler,
+ .name = DRIVER_NAME,
+ .desc = DRIVER_DESC,
+ .date = DRIVER_DATE,
+ .major = DRIVER_MAJOR,
+ .minor = DRIVER_MINOR,
+ .patchlevel = DRIVER_PATCHLEVEL,
+
+ .gem_free_object = vbox_gem_free_object,
+ .dumb_create = vbox_dumb_create,
+ .dumb_map_offset = vbox_dumb_mmap_offset,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0) && !defined(RHEL_73)
+ .dumb_destroy = vbox_dumb_destroy,
+#else
+ .dumb_destroy = drm_gem_dumb_destroy,
+#endif
+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+ .gem_prime_export = drm_gem_prime_export,
+ .gem_prime_import = drm_gem_prime_import,
+ .gem_prime_pin = vbox_gem_prime_pin,
+ .gem_prime_unpin = vbox_gem_prime_unpin,
+ .gem_prime_get_sg_table = vbox_gem_prime_get_sg_table,
+ .gem_prime_import_sg_table = vbox_gem_prime_import_sg_table,
+ .gem_prime_vmap = vbox_gem_prime_vmap,
+ .gem_prime_vunmap = vbox_gem_prime_vunmap,
+ .gem_prime_mmap = vbox_gem_prime_mmap,
+
+};
+
+static int __init vbox_init(void)
+{
+#ifdef CONFIG_VGA_CONSOLE
+ if (vgacon_text_force() && vbox_modeset == -1)
+ return -EINVAL;
+#endif
+
+ if (vbox_modeset == 0)
+ return -EINVAL;
+
+ return drm_pci_init(&driver, &vbox_pci_driver);
+}
+static void __exit vbox_exit(void)
+{
+ drm_pci_exit(&driver, &vbox_pci_driver);
+}
+
+module_init(vbox_init);
+module_exit(vbox_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL and additional rights");
+#ifdef MODULE_VERSION
+MODULE_VERSION(VBOX_VERSION_STRING " r" RT_XSTR(VBOX_SVN_REV));
+#endif
--- /dev/null
+/* $Id: vbox_drv.h $ */
+/** @file
+ * VirtualBox Additions Linux kernel video driver
+ */
+
+/*
+ * Copyright (C) 2013-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on
+ * ast_drv.h
+ * with the following copyright and permission notice:
+ *
+ * Copyright 2012 Red Hat Inc.
+ *
+ * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors: Dave Airlie <airlied@redhat.com>
+ */
+#ifndef __VBOX_DRV_H__
+#define __VBOX_DRV_H__
+
+#define LOG_GROUP LOG_GROUP_DEV_VGA
+
+#include "the-linux-kernel.h"
+
+#include <VBox/VBoxVideoGuest.h>
+#include <VBox/log.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_fb_helper.h>
+
+#include <drm/ttm/ttm_bo_api.h>
+#include <drm/ttm/ttm_bo_driver.h>
+#include <drm/ttm/ttm_placement.h>
+#include <drm/ttm/ttm_memory.h>
+#include <drm/ttm/ttm_module.h>
+
+#if defined(RHEL_MAJOR) && defined(RHEL_MINOR)
+# if RHEL_MAJOR == 7 && RHEL_MINOR >= 4
+# define RHEL_73
+# define RHEL_74
+# elif RHEL_MAJOR == 7 && RHEL_MINOR >= 3
+# define RHEL_73
+# endif
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0) || defined(RHEL_73)
+# include <drm/drm_gem.h>
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+# include <drm/drm_encoder.h>
+#endif
+
+/* #include "vboxvideo.h" */
+
+#include "product-generated.h"
+
+#define DRIVER_AUTHOR VBOX_VENDOR
+
+#define DRIVER_NAME "vboxvideo"
+#define DRIVER_DESC VBOX_PRODUCT " Graphics Card"
+#define DRIVER_DATE "20130823"
+
+#define DRIVER_MAJOR 1
+#define DRIVER_MINOR 0
+#define DRIVER_PATCHLEVEL 0
+
+#define VBOX_MAX_CURSOR_WIDTH 64
+#define VBOX_MAX_CURSOR_HEIGHT 64
+#define CURSOR_PIXEL_COUNT VBOX_MAX_CURSOR_WIDTH * VBOX_MAX_CURSOR_HEIGHT
+#define CURSOR_DATA_SIZE CURSOR_PIXEL_COUNT * 4 + CURSOR_PIXEL_COUNT / 8
+
+#define VBOX_MAX_SCREENS 32
+
+struct vbox_fbdev;
+
+struct vbox_private {
+ struct drm_device *dev;
+
+ uint8_t __iomem *mapped_vram;
+ HGSMIGUESTCOMMANDCONTEXT submit_info;
+ struct VBVABUFFERCONTEXT *vbva_info;
+ bool any_pitch;
+ unsigned num_crtcs;
+ bool vga2_clone;
+ /** Amount of available VRAM, including space used for buffers. */
+ uint32_t full_vram_size;
+ /** Amount of available VRAM, not including space used for buffers. */
+ uint32_t available_vram_size;
+ /** Offset of mapped VRAM area in full VRAM. */
+ uint32_t vram_map_start;
+ /** Offset to the host flags in the VRAM. */
+ uint32_t host_flags_offset;
+ /** Array of structures for receiving mode hints. */
+ VBVAMODEHINT *last_mode_hints;
+
+ struct vbox_fbdev *fbdev;
+
+ int fb_mtrr;
+
+ struct {
+ struct drm_global_reference mem_global_ref;
+ struct ttm_bo_global_ref bo_global_ref;
+ struct ttm_bo_device bdev;
+ bool mm_initialised;
+ } ttm;
+
+ struct mutex hw_mutex;
+ bool isr_installed;
+ /** We decide whether or not user-space supports display hot-plug
+ * depending on whether they react to a hot-plug event after the initial
+ * mode query. */
+ bool initial_mode_queried;
+ struct work_struct hotplug_work;
+ uint32_t input_mapping_width;
+ uint32_t input_mapping_height;
+ uint32_t cursor_width;
+ uint32_t cursor_height;
+ uint32_t cursor_hot_x;
+ uint32_t cursor_hot_y;
+ size_t cursor_data_size;
+ uint8_t cursor_data[CURSOR_DATA_SIZE];
+};
+
+#undef CURSOR_PIXEL_COUNT
+#undef CURSOR_DATA_SIZE
+
+int vbox_driver_load(struct drm_device *dev, unsigned long flags);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+void vbox_driver_unload(struct drm_device *dev);
+#else
+int vbox_driver_unload(struct drm_device *dev);
+#endif
+void vbox_driver_lastclose(struct drm_device *dev);
+
+struct vbox_gem_object;
+
+#ifndef VGA_PORT_HGSMI_HOST
+# define VGA_PORT_HGSMI_HOST 0x3b0
+# define VGA_PORT_HGSMI_GUEST 0x3d0
+#endif
+
+struct vbox_connector {
+ struct drm_connector base;
+ char name[32];
+ struct vbox_crtc *vbox_crtc;
+ struct {
+ uint16_t width;
+ uint16_t height;
+ bool disconnected;
+ } mode_hint;
+};
+
+struct vbox_crtc {
+ struct drm_crtc base;
+ bool blanked;
+ bool disconnected;
+ unsigned crtc_id;
+ uint32_t fb_offset;
+ bool cursor_enabled;
+};
+
+struct vbox_encoder {
+ struct drm_encoder base;
+};
+
+struct vbox_framebuffer {
+ struct drm_framebuffer base;
+ struct drm_gem_object *obj;
+};
+
+struct vbox_fbdev {
+ struct drm_fb_helper helper;
+ struct vbox_framebuffer afb;
+ void *sysram;
+ int size;
+ struct ttm_bo_kmap_obj mapping;
+ int x1, y1, x2, y2; /* dirty rect */
+ spinlock_t dirty_lock;
+};
+
+#define to_vbox_crtc(x) container_of(x, struct vbox_crtc, base)
+#define to_vbox_connector(x) container_of(x, struct vbox_connector, base)
+#define to_vbox_encoder(x) container_of(x, struct vbox_encoder, base)
+#define to_vbox_framebuffer(x) container_of(x, struct vbox_framebuffer, base)
+
+extern int vbox_mode_init(struct drm_device *dev);
+extern void vbox_mode_fini(struct drm_device *dev);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
+# define DRM_MODE_FB_CMD drm_mode_fb_cmd
+#else
+# define DRM_MODE_FB_CMD drm_mode_fb_cmd2
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0) && !defined(RHEL_73)
+# define CRTC_FB(crtc) (crtc)->fb
+#else
+# define CRTC_FB(crtc) (crtc)->primary->fb
+#endif
+
+void vbox_enable_accel(struct vbox_private *vbox);
+void vbox_disable_accel(struct vbox_private *vbox);
+void vbox_report_caps(struct vbox_private *vbox);
+
+void vbox_framebuffer_dirty_rectangles(struct drm_framebuffer *fb,
+ struct drm_clip_rect *rects,
+ unsigned num_rects);
+
+int vbox_framebuffer_init(struct drm_device *dev,
+ struct vbox_framebuffer *vbox_fb,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0) || defined(RHEL_73)
+ const
+#endif
+ struct DRM_MODE_FB_CMD *mode_cmd,
+ struct drm_gem_object *obj);
+
+int vbox_fbdev_init(struct drm_device *dev);
+void vbox_fbdev_fini(struct drm_device *dev);
+void vbox_fbdev_set_suspend(struct drm_device *dev, int state);
+void vbox_fbdev_set_base(struct vbox_private *vbox, unsigned long gpu_addr);
+
+struct vbox_bo {
+ struct ttm_buffer_object bo;
+ struct ttm_placement placement;
+ struct ttm_bo_kmap_obj kmap;
+ struct drm_gem_object gem;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0) && !defined(RHEL_73)
+ u32 placements[3];
+#else
+ struct ttm_place placements[3];
+#endif
+ int pin_count;
+};
+#define gem_to_vbox_bo(gobj) container_of((gobj), struct vbox_bo, gem)
+
+static inline struct vbox_bo *
+vbox_bo(struct ttm_buffer_object *bo)
+{
+ return container_of(bo, struct vbox_bo, bo);
+}
+
+
+#define to_vbox_obj(x) container_of(x, struct vbox_gem_object, base)
+
+extern int vbox_dumb_create(struct drm_file *file,
+ struct drm_device *dev,
+ struct drm_mode_create_dumb *args);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0) && !defined(RHEL_73)
+extern int vbox_dumb_destroy(struct drm_file *file,
+ struct drm_device *dev,
+ uint32_t handle);
+#endif
+
+extern void vbox_gem_free_object(struct drm_gem_object *obj);
+extern int vbox_dumb_mmap_offset(struct drm_file *file,
+ struct drm_device *dev,
+ uint32_t handle,
+ uint64_t *offset);
+
+#define DRM_FILE_PAGE_OFFSET (0x10000000ULL >> PAGE_SHIFT)
+
+int vbox_mm_init(struct vbox_private *vbox);
+void vbox_mm_fini(struct vbox_private *vbox);
+
+int vbox_bo_create(struct drm_device *dev, int size, int align,
+ uint32_t flags, struct vbox_bo **pvboxbo);
+
+int vbox_gem_create(struct drm_device *dev,
+ u32 size, bool iskernel,
+ struct drm_gem_object **obj);
+
+int vbox_bo_pin(struct vbox_bo *bo, u32 pl_flag, u64 *gpu_addr);
+int vbox_bo_unpin(struct vbox_bo *bo);
+
+static inline int vbox_bo_reserve(struct vbox_bo *bo, bool no_wait)
+{
+ int ret;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) || defined(RHEL_74)
+ ret = ttm_bo_reserve(&bo->bo, true, no_wait, NULL);
+#else
+ ret = ttm_bo_reserve(&bo->bo, true, no_wait, false, 0);
+#endif
+ if (ret)
+ {
+ if (ret != -ERESTARTSYS && ret != -EBUSY)
+ DRM_ERROR("reserve failed %p\n", bo);
+ return ret;
+ }
+ return 0;
+}
+
+static inline void vbox_bo_unreserve(struct vbox_bo *bo)
+{
+ ttm_bo_unreserve(&bo->bo);
+}
+
+void vbox_ttm_placement(struct vbox_bo *bo, int domain);
+int vbox_bo_push_sysram(struct vbox_bo *bo);
+int vbox_mmap(struct file *filp, struct vm_area_struct *vma);
+
+/*vbox_prime*/
+int vbox_gem_prime_pin(struct drm_gem_object *obj);
+void vbox_gem_prime_unpin(struct drm_gem_object *obj);
+struct sg_table *vbox_gem_prime_get_sg_table(struct drm_gem_object *obj);
+struct drm_gem_object *vbox_gem_prime_import_sg_table(
+ struct drm_device *dev,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0) && !defined(RHEL_73)
+ size_t size,
+#else
+ struct dma_buf_attachment *attach,
+#endif
+ struct sg_table *table);
+void *vbox_gem_prime_vmap(struct drm_gem_object *obj);
+void vbox_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
+int vbox_gem_prime_mmap(struct drm_gem_object *obj,
+ struct vm_area_struct *area);
+
+/* vbox_irq.c */
+int vbox_irq_init(struct vbox_private *vbox);
+void vbox_irq_fini(struct vbox_private *vbox);
+void vbox_report_hotplug(struct vbox_private *vbox);
+irqreturn_t vbox_irq_handler(int irq, void *arg);
+#endif
--- /dev/null
+/* $Id: vbox_dummy.c $ */
+/** @file
+ * VirtualBox Additions Linux kernel video driver, dummy driver for
+ * older kernels.
+ */
+
+/*
+ * Copyright (C) 2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
+static int __init vbox_init(void)
+{
+ return -EINVAL;
+}
+static void __exit vbox_exit(void)
+{
+}
+
+module_init(vbox_init);
+module_exit(vbox_exit);
+
+MODULE_LICENSE("GPL");
--- /dev/null
+/* $Id: vbox_fb.c $ */
+/** @file
+ * VirtualBox Additions Linux kernel video driver
+ */
+
+/*
+ * Copyright (C) 2013-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on
+ * ast_fb.c
+ * with the following copyright and permission notice:
+ *
+ * Copyright 2012 Red Hat Inc.
+ *
+ * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors: Dave Airlie <airlied@redhat.com>
+ */
+/* Include from most specific to most general to be able to override things. */
+#include "vbox_drv.h"
+#include <VBox/VBoxVideo.h>
+#include <VBox/VMMDev.h>
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/sysrq.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include "vbox_drv.h"
+
+#define VBOX_DIRTY_DELAY (HZ / 30)
+/**
+ * Tell the host about dirty rectangles to update.
+ */
+static void vbox_dirty_update(struct vbox_fbdev *fbdev,
+ int x, int y, int width, int height)
+{
+ int i;
+
+ struct drm_gem_object *obj;
+ struct vbox_bo *bo;
+ int src_offset, dst_offset;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+ int bpp = fbdev->afb.base.format->cpp[0];
+#else
+ int bpp = (fbdev->afb.base.bits_per_pixel + 7) / 8;
+#endif
+ int ret = -EBUSY;
+ bool unmap = false;
+ bool store_for_later = false;
+ int x2, y2;
+ unsigned long flags;
+ struct drm_clip_rect rect;
+
+ LogFunc(("vboxvideo: %d\n", __LINE__));
+ obj = fbdev->afb.obj;
+ bo = gem_to_vbox_bo(obj);
+
+ /*
+ * try and reserve the BO, if we fail with busy
+ * then the BO is being moved and we should
+ * store up the damage until later.
+ */
+ if (drm_can_sleep())
+ ret = vbox_bo_reserve(bo, true);
+ if (ret) {
+ if (ret != -EBUSY)
+ return;
+
+ store_for_later = true;
+ }
+
+ x2 = x + width - 1;
+ y2 = y + height - 1;
+ spin_lock_irqsave(&fbdev->dirty_lock, flags);
+
+ if (fbdev->y1 < y)
+ y = fbdev->y1;
+ if (fbdev->y2 > y2)
+ y2 = fbdev->y2;
+ if (fbdev->x1 < x)
+ x = fbdev->x1;
+ if (fbdev->x2 > x2)
+ x2 = fbdev->x2;
+
+ if (store_for_later) {
+ fbdev->x1 = x;
+ fbdev->x2 = x2;
+ fbdev->y1 = y;
+ fbdev->y2 = y2;
+ spin_unlock_irqrestore(&fbdev->dirty_lock, flags);
+ LogFunc(("vboxvideo: %d\n", __LINE__));
+ return;
+ }
+
+ fbdev->x1 = fbdev->y1 = INT_MAX;
+ fbdev->x2 = fbdev->y2 = 0;
+ spin_unlock_irqrestore(&fbdev->dirty_lock, flags);
+
+ if (!bo->kmap.virtual) {
+ ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
+ if (ret) {
+ DRM_ERROR("failed to kmap fb updates\n");
+ vbox_bo_unreserve(bo);
+ return;
+ }
+ unmap = true;
+ }
+ for (i = y; i <= y2; i++) {
+ /* assume equal stride for now */
+ src_offset = dst_offset = i * fbdev->afb.base.pitches[0] + (x * bpp);
+ memcpy_toio(bo->kmap.virtual + src_offset, (char *)fbdev->sysram + src_offset, (x2 - x + 1) * bpp);
+ }
+ /* Not sure why the original code subtracted 1 here, but I will keep it that
+ * way to avoid unnecessary differences. */
+ rect.x1 = x;
+ rect.x2 = x2 + 1;
+ rect.y1 = y;
+ rect.y2 = y2 + 1;
+ vbox_framebuffer_dirty_rectangles(&fbdev->afb.base, &rect, 1);
+ LogFunc(("vboxvideo: %d, bo->kmap.virtual=%p, fbdev->sysram=%p, x=%d, y=%d, x2=%d, y2=%d, unmap=%RTbool\n",
+ __LINE__, bo->kmap.virtual, fbdev->sysram, (int)x, (int)y, (int)x2, (int)y2, unmap));
+ if (unmap)
+ ttm_bo_kunmap(&bo->kmap);
+
+ vbox_bo_unreserve(bo);
+}
+
+#ifdef CONFIG_FB_DEFERRED_IO
+static void vbox_deferred_io(struct fb_info *info,
+ struct list_head *pagelist)
+{
+ struct vbox_fbdev *fbdev = info->par;
+ unsigned long start, end, min, max;
+ struct page *page;
+ int y1, y2;
+
+ min = ULONG_MAX;
+ max = 0;
+ list_for_each_entry(page, pagelist, lru) {
+ start = page->index << PAGE_SHIFT;
+ end = start + PAGE_SIZE - 1;
+ min = min(min, start);
+ max = max(max, end);
+ }
+
+ if (min < max) {
+ y1 = min / info->fix.line_length;
+ y2 = (max / info->fix.line_length) + 1;
+ printk(KERN_INFO "%s: Calling dirty update: 0, %d, %d, %d\n",
+ __func__, y1, info->var.xres, y2 - y1 - 1);
+ vbox_dirty_update(fbdev, 0, y1, info->var.xres, y2 - y1 - 1);
+ }
+}
+
+static struct fb_deferred_io vbox_defio =
+{
+ .delay = VBOX_DIRTY_DELAY,
+ .deferred_io = vbox_deferred_io,
+};
+#endif
+
+static void vbox_fillrect(struct fb_info *info,
+ const struct fb_fillrect *rect)
+{
+ struct vbox_fbdev *fbdev = info->par;
+ LogFunc(("vboxvideo: %d\n", __LINE__));
+ sys_fillrect(info, rect);
+ vbox_dirty_update(fbdev, rect->dx, rect->dy, rect->width,
+ rect->height);
+}
+
+static void vbox_copyarea(struct fb_info *info,
+ const struct fb_copyarea *area)
+{
+ struct vbox_fbdev *fbdev = info->par;
+ LogFunc(("vboxvideo: %d\n", __LINE__));
+ sys_copyarea(info, area);
+ vbox_dirty_update(fbdev, area->dx, area->dy, area->width,
+ area->height);
+}
+
+static void vbox_imageblit(struct fb_info *info,
+ const struct fb_image *image)
+{
+ struct vbox_fbdev *fbdev = info->par;
+ LogFunc(("vboxvideo: %d\n", __LINE__));
+ sys_imageblit(info, image);
+ vbox_dirty_update(fbdev, image->dx, image->dy, image->width,
+ image->height);
+}
+
+static struct fb_ops vboxfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = drm_fb_helper_check_var,
+ .fb_set_par = drm_fb_helper_set_par,
+ .fb_fillrect = vbox_fillrect,
+ .fb_copyarea = vbox_copyarea,
+ .fb_imageblit = vbox_imageblit,
+ .fb_pan_display = drm_fb_helper_pan_display,
+ .fb_blank = drm_fb_helper_blank,
+ .fb_setcmap = drm_fb_helper_setcmap,
+ .fb_debug_enter = drm_fb_helper_debug_enter,
+ .fb_debug_leave = drm_fb_helper_debug_leave,
+};
+
+static int vboxfb_create_object(struct vbox_fbdev *fbdev,
+ struct DRM_MODE_FB_CMD *mode_cmd,
+ struct drm_gem_object **gobj_p)
+{
+ struct drm_device *dev = fbdev->helper.dev;
+ u32 size;
+ struct drm_gem_object *gobj;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
+ __u32 pitch = mode_cmd->pitch;
+#else
+ __u32 pitch = mode_cmd->pitches[0];
+#endif
+
+ int ret = 0;
+ LogFunc(("vboxvideo: %d\n", __LINE__));
+
+ size = pitch * mode_cmd->height;
+ ret = vbox_gem_create(dev, size, true, &gobj);
+ if (ret)
+ return ret;
+
+ *gobj_p = gobj;
+ LogFunc(("vboxvideo: %d\n", __LINE__));
+ return ret;
+}
+
+static int vboxfb_create(struct drm_fb_helper *helper,
+ struct drm_fb_helper_surface_size *sizes)
+{
+ struct vbox_fbdev *fbdev =
+ container_of(helper, struct vbox_fbdev, helper);
+ struct drm_device *dev = fbdev->helper.dev;
+ struct DRM_MODE_FB_CMD mode_cmd;
+ struct drm_framebuffer *fb;
+ struct fb_info *info;
+ __u32 pitch;
+ int size, ret;
+ struct device *device = &dev->pdev->dev;
+ void *sysram;
+ struct drm_gem_object *gobj = NULL;
+ struct vbox_bo *bo = NULL;
+ LogFunc(("vboxvideo: %d\n", __LINE__));
+ mode_cmd.width = sizes->surface_width;
+ mode_cmd.height = sizes->surface_height;
+ pitch = mode_cmd.width * ((sizes->surface_bpp + 7) / 8);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
+ mode_cmd.bpp = sizes->surface_bpp;
+ mode_cmd.depth = sizes->surface_depth;
+ mode_cmd.pitch = pitch;
+#else
+ mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+ sizes->surface_depth);
+ mode_cmd.pitches[0] = pitch;
+#endif
+
+ size = pitch * mode_cmd.height;
+
+ ret = vboxfb_create_object(fbdev, &mode_cmd, &gobj);
+ if (ret) {
+ DRM_ERROR("failed to create fbcon backing object %d\n", ret);
+ return ret;
+ }
+ bo = gem_to_vbox_bo(gobj);
+
+ sysram = vmalloc(size);
+ if (!sysram)
+ return -ENOMEM;
+
+ info = framebuffer_alloc(0, device);
+ if (!info) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ info->par = fbdev;
+
+ ret = vbox_framebuffer_init(dev, &fbdev->afb, &mode_cmd, gobj);
+ if (ret)
+ goto out;
+
+ fbdev->sysram = sysram;
+ fbdev->size = size;
+
+ fb = &fbdev->afb.base;
+ fbdev->helper.fb = fb;
+ fbdev->helper.fbdev = info;
+
+ strcpy(info->fix.id, "vboxdrmfb");
+
+ /* The last flag forces a mode set on VT switches even if the kernel does
+ * not think it is needed. */
+ info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT
+ | FBINFO_MISC_ALWAYS_SETPAR;
+ info->fbops = &vboxfb_ops;
+
+ ret = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (ret) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* This seems to be done for safety checking that the framebuffer is not
+ * registered twice by different drivers. */
+ info->apertures = alloc_apertures(1);
+ if (!info->apertures) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ info->apertures->ranges[0].base = pci_resource_start(dev->pdev, 0);
+ info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 0);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+ drm_fb_helper_fill_fix(info, fb->pitches[0], fb->format->depth);
+#else
+ drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
+#endif
+ drm_fb_helper_fill_var(info, &fbdev->helper, sizes->fb_width, sizes->fb_height);
+
+ info->screen_base = sysram;
+ info->screen_size = size;
+
+#ifdef CONFIG_FB_DEFERRED_IO
+ info->fbdefio = &vbox_defio;
+ fb_deferred_io_init(info);
+#endif
+
+ info->pixmap.flags = FB_PIXMAP_SYSTEM;
+
+ DRM_DEBUG_KMS("allocated %dx%d\n",
+ fb->width, fb->height);
+
+ LogFunc(("vboxvideo: %d\n", __LINE__));
+ return 0;
+out:
+ LogFunc(("vboxvideo: %d\n", __LINE__));
+ return ret;
+}
+
+static void vbox_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
+ u16 blue, int regno)
+{
+
+}
+
+static void vbox_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
+ u16 *blue, int regno)
+{
+ *red = regno;
+ *green = regno;
+ *blue = regno;
+}
+
+static struct drm_fb_helper_funcs vbox_fb_helper_funcs = {
+ .gamma_set = vbox_fb_gamma_set,
+ .gamma_get = vbox_fb_gamma_get,
+ .fb_probe = vboxfb_create,
+};
+
+static void vbox_fbdev_destroy(struct drm_device *dev,
+ struct vbox_fbdev *fbdev)
+{
+ struct fb_info *info;
+ struct vbox_framebuffer *afb = &fbdev->afb;
+ LogFunc(("vboxvideo: %d\n", __LINE__));
+ if (fbdev->helper.fbdev) {
+ info = fbdev->helper.fbdev;
+ unregister_framebuffer(info);
+ if (info->cmap.len)
+ fb_dealloc_cmap(&info->cmap);
+ framebuffer_release(info);
+ }
+
+ if (afb->obj) {
+ drm_gem_object_unreference_unlocked(afb->obj);
+ afb->obj = NULL;
+ }
+ drm_fb_helper_fini(&fbdev->helper);
+
+ vfree(fbdev->sysram);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+ drm_framebuffer_unregister_private(&afb->base);
+#endif
+ drm_framebuffer_cleanup(&afb->base);
+ LogFunc(("vboxvideo: %d\n", __LINE__));
+}
+
+int vbox_fbdev_init(struct drm_device *dev)
+{
+ struct vbox_private *vbox = dev->dev_private;
+ struct vbox_fbdev *fbdev;
+ int ret;
+
+ LogFunc(("vboxvideo: %d\n", __LINE__));
+ fbdev = kzalloc(sizeof(struct vbox_fbdev), GFP_KERNEL);
+ if (!fbdev)
+ return -ENOMEM;
+
+ vbox->fbdev = fbdev;
+ spin_lock_init(&fbdev->dirty_lock);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) && !defined(RHEL_73)
+ fbdev->helper.funcs = &vbox_fb_helper_funcs;
+#else
+ drm_fb_helper_prepare(dev, &fbdev->helper, &vbox_fb_helper_funcs);
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+ ret = drm_fb_helper_init(dev, &fbdev->helper, vbox->num_crtcs);
+#else
+ ret = drm_fb_helper_init(dev, &fbdev->helper, vbox->num_crtcs, vbox->num_crtcs);
+#endif
+ if (ret)
+ goto free;
+
+ ret = drm_fb_helper_single_add_all_connectors(&fbdev->helper);
+ if (ret)
+ goto fini;
+
+ /* disable all the possible outputs/crtcs before entering KMS mode */
+ drm_helper_disable_unused_functions(dev);
+
+ ret = drm_fb_helper_initial_config(&fbdev->helper, 32);
+ if (ret)
+ goto fini;
+
+ LogFunc(("vboxvideo: %d\n", __LINE__));
+ return 0;
+fini:
+ drm_fb_helper_fini(&fbdev->helper);
+free:
+ kfree(fbdev);
+ vbox->fbdev = NULL;
+ LogFunc(("vboxvideo: %d, ret=%d\n", __LINE__, ret));
+ return ret;
+}
+
+void vbox_fbdev_fini(struct drm_device *dev)
+{
+ struct vbox_private *vbox = dev->dev_private;
+
+ if (!vbox->fbdev)
+ return;
+
+ LogFunc(("vboxvideo: %d\n", __LINE__));
+ vbox_fbdev_destroy(dev, vbox->fbdev);
+ kfree(vbox->fbdev);
+ vbox->fbdev = NULL;
+}
+
+void vbox_fbdev_set_suspend(struct drm_device *dev, int state)
+{
+ struct vbox_private *vbox = dev->dev_private;
+
+ LogFunc(("vboxvideo: %d\n", __LINE__));
+ if (!vbox->fbdev)
+ return;
+
+ fb_set_suspend(vbox->fbdev->helper.fbdev, state);
+}
+
+void vbox_fbdev_set_base(struct vbox_private *vbox, unsigned long gpu_addr)
+{
+ vbox->fbdev->helper.fbdev->fix.smem_start =
+ vbox->fbdev->helper.fbdev->apertures->ranges[0].base +
+ gpu_addr;
+ vbox->fbdev->helper.fbdev->fix.smem_len = vbox->available_vram_size - gpu_addr;
+}
--- /dev/null
+/* $Id: vbox_irq.c $ */
+/** @file
+ * VirtualBox Additions Linux kernel video driver
+ */
+
+/*
+ * Copyright (C) 2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on
+ * qxl_irq.c
+ * with the following copyright and permission notice:
+ *
+ * Copyright 2013 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: Dave Airlie
+ * Alon Levy
+ */
+
+#include "vbox_drv.h"
+
+#include <VBox/VBoxVideo.h>
+
+#include <drm/drm_crtc_helper.h>
+
+static void vbox_clear_irq(void)
+{
+ outl((uint32_t)~0, VGA_PORT_HGSMI_HOST);
+}
+
+static uint32_t vbox_get_flags(struct vbox_private *vbox)
+{
+ return (uint32_t)readl(vbox->mapped_vram + vbox->host_flags_offset);
+}
+
+void vbox_report_hotplug(struct vbox_private *vbox)
+{
+ schedule_work(&vbox->hotplug_work);
+}
+
+irqreturn_t vbox_irq_handler(int irq, void *arg)
+{
+ struct drm_device *dev = (struct drm_device *) arg;
+ struct vbox_private *vbox = (struct vbox_private *)dev->dev_private;
+ uint32_t host_flags = vbox_get_flags(vbox);
+
+ if (!(host_flags & HGSMIHOSTFLAGS_IRQ))
+ return IRQ_NONE;
+
+ /* Due to a bug in the initial host implementation of hot-plug interrupts,
+ * the hot-plug and cursor capability flags were never cleared. Fortunately
+ * we can tell when they would have been set by checking that the VSYNC flag
+ * is not set. */
+ if ( host_flags & (HGSMIHOSTFLAGS_HOTPLUG | HGSMIHOSTFLAGS_CURSOR_CAPABILITIES)
+ && !(host_flags & HGSMIHOSTFLAGS_VSYNC))
+ vbox_report_hotplug(vbox);
+ vbox_clear_irq();
+ return IRQ_HANDLED;
+}
+
+/**
+ * Query the host for
+ */
+static void vbox_update_mode_hints(struct vbox_private *vbox)
+{
+ struct drm_device *dev = vbox->dev;
+ struct drm_connector *connector;
+ struct vbox_connector *vbox_connector;
+ struct VBVAMODEHINT *hints;
+ uint16_t flags;
+ bool disconnected;
+ unsigned crtc_id;
+ int rc;
+
+ rc = VBoxHGSMIGetModeHints(&vbox->submit_info, vbox->num_crtcs,
+ vbox->last_mode_hints);
+ AssertMsgRCReturnVoid(rc, ("VBoxHGSMIGetModeHints failed, rc=%Rrc.\n", rc));
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+ drm_modeset_lock_all(dev);
+#else
+ mutex_lock(&dev->mode_config.mutex);
+#endif
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ vbox_connector = to_vbox_connector(connector);
+ hints = &vbox->last_mode_hints[vbox_connector->vbox_crtc->crtc_id];
+ if (hints->magic == VBVAMODEHINT_MAGIC) {
+ LogFunc(("vboxvideo: %d: crtc_id=%u, mode %hdx%hd(enabled:%d),%hdx%hd\n",
+ __LINE__, (unsigned)vbox_connector->vbox_crtc->crtc_id,
+ (short)hints->cx, (short)hints->cy, (int)hints->fEnabled,
+ (short)hints->dx, (short)hints->dy));
+ disconnected = !(hints->fEnabled);
+ crtc_id = vbox_connector->vbox_crtc->crtc_id;
+ flags = VBVA_SCREEN_F_ACTIVE
+ | (disconnected ? VBVA_SCREEN_F_DISABLED : VBVA_SCREEN_F_BLANK);
+ vbox_connector->mode_hint.width = hints->cx & 0x8fff;
+ vbox_connector->mode_hint.height = hints->cy & 0x8fff;
+ vbox_connector->mode_hint.disconnected = disconnected;
+ if (vbox_connector->vbox_crtc->disconnected != disconnected) {
+ VBoxHGSMIProcessDisplayInfo(&vbox->submit_info, crtc_id,
+ 0, 0, 0, hints->cx * 4, hints->cx,
+ hints->cy, 0, flags);
+ vbox_connector->vbox_crtc->disconnected = disconnected;
+ }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) || defined(RHEL_73)
+ if ((hints->dx < 0xffff) && (hints->dy < 0xffff)) {
+ drm_object_property_set_value(&connector->base,
+ dev->mode_config.suggested_x_property, hints->dx & 0x8fff);
+ drm_object_property_set_value(&connector->base,
+ dev->mode_config.suggested_y_property, hints->dy & 0x8fff);
+ }
+#endif
+ }
+ }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+ drm_modeset_unlock_all(dev);
+#else
+ mutex_unlock(&dev->mode_config.mutex);
+#endif
+}
+
+static void vbox_hotplug_worker(struct work_struct *work)
+{
+ struct vbox_private *vbox = container_of(work, struct vbox_private,
+ hotplug_work);
+
+ LogFunc(("vboxvideo: %d: vbox=%p\n", __LINE__, vbox));
+ vbox_update_mode_hints(vbox);
+ drm_kms_helper_hotplug_event(vbox->dev);
+}
+
+int vbox_irq_init(struct vbox_private *vbox)
+{
+ int ret;
+
+ LogFunc(("vboxvideo: %d: vbox=%p\n", __LINE__, vbox));
+ vbox_update_mode_hints(vbox);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) || defined(RHEL_73)
+ ret = drm_irq_install(vbox->dev, vbox->dev->pdev->irq);
+#else
+ ret = drm_irq_install(vbox->dev);
+#endif
+ if (unlikely(ret != 0)) {
+ vbox_irq_fini(vbox);
+ DRM_ERROR("Failed installing irq: %d\n", ret);
+ return 1;
+ }
+ INIT_WORK(&vbox->hotplug_work, vbox_hotplug_worker);
+ vbox->isr_installed = true;
+ LogFunc(("vboxvideo: %d: vbox=%p\n", __LINE__, vbox));
+ return 0;
+}
+
+void vbox_irq_fini(struct vbox_private *vbox)
+{
+ LogFunc(("vboxvideo: %d: vbox=%p\n", __LINE__, vbox));
+ if (vbox->isr_installed) {
+ drm_irq_uninstall(vbox->dev);
+ flush_work(&vbox->hotplug_work);
+ vbox->isr_installed = false;
+ }
+}
--- /dev/null
+/* $Id: vbox_main.c $ */
+/** @file
+ * VirtualBox Additions Linux kernel video driver
+ */
+
+/*
+ * Copyright (C) 2013-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on
+ * ast_main.c
+ * with the following copyright and permission notice:
+ *
+ * Copyright 2012 Red Hat Inc.
+ *
+ * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors: Dave Airlie <airlied@redhat.com>
+ */
+#include "vbox_drv.h"
+
+#include <VBox/VBoxVideoGuest.h>
+#include <VBox/VBoxVideo.h>
+
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_crtc_helper.h>
+
+static void vbox_user_framebuffer_destroy(struct drm_framebuffer *fb)
+{
+ struct vbox_framebuffer *vbox_fb = to_vbox_framebuffer(fb);
+ if (vbox_fb->obj)
+ drm_gem_object_unreference_unlocked(vbox_fb->obj);
+
+ LogFunc(("vboxvideo: %d: vbox_fb=%p, vbox_fb->obj=%p\n", __LINE__,
+ vbox_fb, vbox_fb->obj));
+ drm_framebuffer_cleanup(fb);
+ kfree(fb);
+}
+
+void vbox_enable_accel(struct vbox_private *vbox)
+{
+ unsigned i;
+ struct VBVABUFFER *vbva;
+ uint32_t vram_map_offset = vbox->available_vram_size - vbox->vram_map_start;
+
+ AssertLogRelReturnVoid(vbox->vbva_info != NULL);
+ for (i = 0; i < vbox->num_crtcs; ++i) {
+ if (vbox->vbva_info[i].pVBVA == NULL) {
+ LogFunc(("vboxvideo: enabling VBVA.\n"));
+ vbva = (struct VBVABUFFER *) ( ((uint8_t *)vbox->mapped_vram)
+ + vram_map_offset
+ + i * VBVA_MIN_BUFFER_SIZE);
+ if (!VBoxVBVAEnable(&vbox->vbva_info[i], &vbox->submit_info, vbva, i))
+ AssertReleaseMsgFailed(("VBoxVBVAEnable failed - heap allocation error, very old host or driver error.\n"));
+ }
+ }
+}
+
+void vbox_disable_accel(struct vbox_private *vbox)
+{
+ unsigned i;
+
+ for (i = 0; i < vbox->num_crtcs; ++i)
+ VBoxVBVADisable(&vbox->vbva_info[i], &vbox->submit_info, i);
+}
+
+void vbox_report_caps(struct vbox_private *vbox)
+{
+ uint32_t caps = VBVACAPS_DISABLE_CURSOR_INTEGRATION
+ | VBVACAPS_IRQ
+ | VBVACAPS_USE_VBVA_ONLY;
+ if (vbox->initial_mode_queried)
+ caps |= VBVACAPS_VIDEO_MODE_HINTS;
+ VBoxHGSMISendCapsInfo(&vbox->submit_info, caps);
+}
+
+/** Send information about dirty rectangles to VBVA. If necessary we enable
+ * VBVA first, as this is normally disabled after a change of master in case
+ * the new master does not send dirty rectangle information (is this even
+ * allowed?) */
+void vbox_framebuffer_dirty_rectangles(struct drm_framebuffer *fb,
+ struct drm_clip_rect *rects,
+ unsigned num_rects)
+{
+ struct vbox_private *vbox = fb->dev->dev_private;
+ struct drm_crtc *crtc;
+ unsigned i;
+
+ LogFunc(("vboxvideo: %d: fb=%p, num_rects=%u, vbox=%p\n", __LINE__, fb,
+ num_rects, vbox));
+ mutex_lock(&vbox->hw_mutex);
+ list_for_each_entry(crtc, &fb->dev->mode_config.crtc_list, head) {
+ if (CRTC_FB(crtc) == fb) {
+ vbox_enable_accel(vbox);
+ for (i = 0; i < num_rects; ++i)
+ {
+ unsigned crtc_id = to_vbox_crtc(crtc)->crtc_id;
+ VBVACMDHDR cmd_hdr;
+
+ if ( rects[i].x1 > crtc->x
+ + crtc->hwmode.hdisplay
+ || rects[i].y1 > crtc->y
+ + crtc->hwmode.vdisplay
+ || rects[i].x2 < crtc->x
+ || rects[i].y2 < crtc->y)
+ continue;
+ cmd_hdr.x = (int16_t)rects[i].x1;
+ cmd_hdr.y = (int16_t)rects[i].y1;
+ cmd_hdr.w = (uint16_t)rects[i].x2 - rects[i].x1;
+ cmd_hdr.h = (uint16_t)rects[i].y2 - rects[i].y1;
+ if (VBoxVBVABufferBeginUpdate(&vbox->vbva_info[crtc_id],
+ &vbox->submit_info))
+ {
+ VBoxVBVAWrite(&vbox->vbva_info[crtc_id], &vbox->submit_info, &cmd_hdr,
+ sizeof(cmd_hdr));
+ VBoxVBVABufferEndUpdate(&vbox->vbva_info[crtc_id]);
+ }
+ }
+ }
+ }
+ mutex_unlock(&vbox->hw_mutex);
+ LogFunc(("vboxvideo: %d\n", __LINE__));
+}
+
+static int vbox_user_framebuffer_dirty(struct drm_framebuffer *fb,
+ struct drm_file *file_priv,
+ unsigned flags, unsigned color,
+ struct drm_clip_rect *rects,
+ unsigned num_rects)
+{
+ vbox_framebuffer_dirty_rectangles(fb, rects, num_rects);
+ return 0;
+}
+
+static const struct drm_framebuffer_funcs vbox_fb_funcs = {
+ .destroy = vbox_user_framebuffer_destroy,
+ .dirty = vbox_user_framebuffer_dirty,
+};
+
+
+int vbox_framebuffer_init(struct drm_device *dev,
+ struct vbox_framebuffer *vbox_fb,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0) || defined(RHEL_73)
+ const
+#endif
+ struct DRM_MODE_FB_CMD *mode_cmd,
+ struct drm_gem_object *obj)
+{
+ int ret;
+
+ LogFunc(("vboxvideo: %d: dev=%p, vbox_fb=%p, obj=%p\n", __LINE__, dev,
+ vbox_fb, obj));
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+ drm_helper_mode_fill_fb_struct(dev, &vbox_fb->base, mode_cmd);
+#else
+ drm_helper_mode_fill_fb_struct(&vbox_fb->base, mode_cmd);
+#endif
+ vbox_fb->obj = obj;
+ ret = drm_framebuffer_init(dev, &vbox_fb->base, &vbox_fb_funcs);
+ if (ret) {
+ DRM_ERROR("framebuffer init failed %d\n", ret);
+ LogFunc(("vboxvideo: %d\n", __LINE__));
+ return ret;
+ }
+ LogFunc(("vboxvideo: %d\n", __LINE__));
+ return 0;
+}
+
+static struct drm_framebuffer *
+vbox_user_framebuffer_create(struct drm_device *dev,
+ struct drm_file *filp,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0) || defined(RHEL_73)
+ const
+#endif
+ struct drm_mode_fb_cmd2 *mode_cmd)
+{
+ struct drm_gem_object *obj;
+ struct vbox_framebuffer *vbox_fb;
+ int ret;
+
+ LogFunc(("vboxvideo: %d\n", __LINE__));
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) || defined(RHEL_74)
+ obj = drm_gem_object_lookup(filp, mode_cmd->handles[0]);
+#else
+ obj = drm_gem_object_lookup(dev, filp, mode_cmd->handles[0]);
+#endif
+ if (obj == NULL)
+ return ERR_PTR(-ENOENT);
+
+ vbox_fb = kzalloc(sizeof(*vbox_fb), GFP_KERNEL);
+ if (!vbox_fb) {
+ drm_gem_object_unreference_unlocked(obj);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ ret = vbox_framebuffer_init(dev, vbox_fb, mode_cmd, obj);
+ if (ret) {
+ drm_gem_object_unreference_unlocked(obj);
+ kfree(vbox_fb);
+ return ERR_PTR(ret);
+ }
+ LogFunc(("vboxvideo: %d\n", __LINE__));
+ return &vbox_fb->base;
+}
+
+static const struct drm_mode_config_funcs vbox_mode_funcs = {
+ .fb_create = vbox_user_framebuffer_create,
+};
+
+static void vbox_accel_fini(struct vbox_private *vbox)
+{
+ if (vbox->vbva_info)
+ {
+ vbox_disable_accel(vbox);
+ kfree(vbox->vbva_info);
+ vbox->vbva_info = NULL;
+ }
+}
+
+static int vbox_accel_init(struct vbox_private *vbox)
+{
+ unsigned i;
+ LogFunc(("vboxvideo: %d: vbox=%p, vbox->num_crtcs=%u, vbox->vbva_info=%p\n",
+ __LINE__, vbox, (unsigned)vbox->num_crtcs, vbox->vbva_info));
+ if (!vbox->vbva_info)
+ {
+ vbox->vbva_info = kzalloc( sizeof(struct VBVABUFFERCONTEXT)
+ * vbox->num_crtcs,
+ GFP_KERNEL);
+ if (!vbox->vbva_info)
+ return -ENOMEM;
+ }
+ /* Take a command buffer for each screen from the end of usable VRAM. */
+ vbox->available_vram_size -= vbox->num_crtcs * VBVA_MIN_BUFFER_SIZE;
+ for (i = 0; i < vbox->num_crtcs; ++i)
+ VBoxVBVASetupBufferContext(&vbox->vbva_info[i],
+ vbox->available_vram_size + i * VBVA_MIN_BUFFER_SIZE,
+ VBVA_MIN_BUFFER_SIZE);
+ LogFunc(("vboxvideo: %d: vbox->vbva_info=%p, vbox->available_vram_size=%u\n",
+ __LINE__, vbox->vbva_info, (unsigned)vbox->available_vram_size));
+ return 0;
+}
+
+/** Allocation function for the HGSMI heap and data. */
+static DECLCALLBACK(void *) alloc_hgsmi_environ(void *environ, HGSMISIZE size)
+{
+ NOREF(environ);
+ return kmalloc(size, GFP_KERNEL);
+}
+
+
+/** Free function for the HGSMI heap and data. */
+static DECLCALLBACK(void) free_hgsmi_environ(void *environ, void *ptr)
+{
+ NOREF(environ);
+ kfree(ptr);
+}
+
+
+/** Pointers to the HGSMI heap and data manipulation functions. */
+static HGSMIENV hgsmi_environ =
+{
+ NULL,
+ alloc_hgsmi_environ,
+ free_hgsmi_environ
+};
+
+
+/** Do we support the 4.3 plus mode hint reporting interface? */
+static bool have_hgsmi_mode_hints(struct vbox_private *vbox)
+{
+ uint32_t have_hints, have_cursor;
+
+ return RT_SUCCESS(VBoxQueryConfHGSMI(&vbox->submit_info, VBOX_VBVA_CONF32_MODE_HINT_REPORTING, &have_hints))
+ && RT_SUCCESS(VBoxQueryConfHGSMI(&vbox->submit_info, VBOX_VBVA_CONF32_GUEST_CURSOR_REPORTING, &have_cursor))
+ && have_hints == VINF_SUCCESS
+ && have_cursor == VINF_SUCCESS;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0) && !defined(RHEL_73)
+# define pci_iomap_range(dev, bar, offset, maxlen) \
+ ioremap(pci_resource_start(dev, bar) + offset, maxlen)
+#endif
+
+/** Set up our heaps and data exchange buffers in VRAM before handing the rest
+ * to the memory manager. */
+static int vbox_hw_init(struct vbox_private *vbox)
+{
+ uint32_t base_offset, map_start, guest_heap_offset, guest_heap_size, host_flags_offset;
+ void *guest_heap;
+
+ vbox->full_vram_size = VBoxVideoGetVRAMSize();
+ vbox->any_pitch = VBoxVideoAnyWidthAllowed();
+ DRM_INFO("VRAM %08x\n", vbox->full_vram_size);
+ VBoxHGSMIGetBaseMappingInfo(vbox->full_vram_size, &base_offset, NULL,
+ &guest_heap_offset, &guest_heap_size, &host_flags_offset);
+ map_start = (uint32_t)max((int)base_offset
+ - VBOX_MAX_SCREENS * VBVA_MIN_BUFFER_SIZE, 0);
+ vbox->mapped_vram = pci_iomap_range(vbox->dev->pdev, 0, map_start,
+ vbox->full_vram_size - map_start);
+ if (!vbox->mapped_vram)
+ return -ENOMEM;
+ vbox->vram_map_start = map_start;
+ guest_heap = ((uint8_t *)vbox->mapped_vram) + base_offset - map_start
+ + guest_heap_offset;
+ vbox->host_flags_offset = base_offset - map_start + host_flags_offset;
+ if (RT_FAILURE(VBoxHGSMISetupGuestContext(&vbox->submit_info, guest_heap,
+ guest_heap_size,
+ base_offset + guest_heap_offset,
+ &hgsmi_environ)))
+ return -ENOMEM;
+ /* Reduce available VRAM size to reflect the guest heap. */
+ vbox->available_vram_size = base_offset;
+ /* Linux drm represents monitors as a 32-bit array. */
+ vbox->num_crtcs = min(VBoxHGSMIGetMonitorCount(&vbox->submit_info),
+ (uint32_t)VBOX_MAX_SCREENS);
+ if (!have_hgsmi_mode_hints(vbox))
+ return -ENOTSUPP;
+ vbox->last_mode_hints = kzalloc(sizeof(VBVAMODEHINT) * vbox->num_crtcs, GFP_KERNEL);
+ if (!vbox->last_mode_hints)
+ return -ENOMEM;
+ return vbox_accel_init(vbox);
+}
+
+static void vbox_hw_fini(struct vbox_private *vbox)
+{
+ vbox_accel_fini(vbox);
+ if (vbox->last_mode_hints)
+ kfree(vbox->last_mode_hints);
+ vbox->last_mode_hints = NULL;
+}
+
+int vbox_driver_load(struct drm_device *dev, unsigned long flags)
+{
+ struct vbox_private *vbox;
+ int ret = 0;
+
+ LogFunc(("vboxvideo: %d: dev=%p\n", __LINE__, dev));
+ if (!VBoxHGSMIIsSupported())
+ return -ENODEV;
+ vbox = kzalloc(sizeof(struct vbox_private), GFP_KERNEL);
+ if (!vbox)
+ return -ENOMEM;
+
+ dev->dev_private = vbox;
+ vbox->dev = dev;
+
+ mutex_init(&vbox->hw_mutex);
+
+ ret = vbox_hw_init(vbox);
+ if (ret)
+ goto out_free;
+
+ ret = vbox_mm_init(vbox);
+ if (ret)
+ goto out_free;
+
+ drm_mode_config_init(dev);
+
+ dev->mode_config.funcs = (void *)&vbox_mode_funcs;
+ dev->mode_config.min_width = 64;
+ dev->mode_config.min_height = 64;
+ dev->mode_config.preferred_depth = 24;
+ dev->mode_config.max_width = VBE_DISPI_MAX_XRES;
+ dev->mode_config.max_height = VBE_DISPI_MAX_YRES;
+
+ ret = vbox_mode_init(dev);
+ if (ret)
+ goto out_free;
+
+ ret = vbox_irq_init(vbox);
+ if (ret)
+ goto out_free;
+
+ ret = vbox_fbdev_init(dev);
+ if (ret)
+ goto out_free;
+ LogFunc(("vboxvideo: %d: vbox=%p, vbox->mapped_vram=%p, vbox->full_vram_size=%u\n",
+ __LINE__, vbox, vbox->mapped_vram, (unsigned)vbox->full_vram_size));
+ return 0;
+out_free:
+ vbox_driver_unload(dev);
+ LogFunc(("vboxvideo: %d: ret=%d\n", __LINE__, ret));
+ return ret;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+void vbox_driver_unload(struct drm_device *dev)
+#else
+int vbox_driver_unload(struct drm_device *dev)
+#endif
+{
+ struct vbox_private *vbox = dev->dev_private;
+
+ LogFunc(("vboxvideo: %d\n", __LINE__));
+ vbox_fbdev_fini(dev);
+ vbox_irq_fini(vbox);
+ vbox_mode_fini(dev);
+ if (dev->mode_config.funcs)
+ drm_mode_config_cleanup(dev);
+
+ vbox_hw_fini(vbox);
+ vbox_mm_fini(vbox);
+ if (vbox->mapped_vram)
+ pci_iounmap(dev->pdev, vbox->mapped_vram);
+ kfree(vbox);
+ dev->dev_private = NULL;
+ LogFunc(("vboxvideo: %d\n", __LINE__));
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
+ return 0;
+#endif
+}
+
+/** @note this is described in the DRM framework documentation. AST does not
+ * have it, but we get an oops on driver unload if it is not present. */
+void vbox_driver_lastclose(struct drm_device *dev)
+{
+ struct vbox_private *vbox = dev->dev_private;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) || defined(RHEL_73)
+ if (vbox->fbdev)
+ drm_fb_helper_restore_fbdev_mode_unlocked(&vbox->fbdev->helper);
+#else
+ drm_modeset_lock_all(dev);
+ if (vbox->fbdev)
+ drm_fb_helper_restore_fbdev_mode(&vbox->fbdev->helper);
+ drm_modeset_unlock_all(dev);
+#endif
+}
+
+int vbox_gem_create(struct drm_device *dev,
+ u32 size, bool iskernel,
+ struct drm_gem_object **obj)
+{
+ struct vbox_bo *vboxbo;
+ int ret;
+
+ LogFunc(("vboxvideo: %d: dev=%p, size=%u, iskernel=%u\n", __LINE__,
+ dev, (unsigned)size, (unsigned)iskernel));
+ *obj = NULL;
+
+ size = roundup(size, PAGE_SIZE);
+ if (size == 0)
+ return -EINVAL;
+
+ ret = vbox_bo_create(dev, size, 0, 0, &vboxbo);
+ if (ret) {
+ if (ret != -ERESTARTSYS)
+ DRM_ERROR("failed to allocate GEM object\n");
+ return ret;
+ }
+ *obj = &vboxbo->gem;
+ LogFunc(("vboxvideo: %d: obj=%p\n", __LINE__, obj));
+ return 0;
+}
+
+int vbox_dumb_create(struct drm_file *file,
+ struct drm_device *dev,
+ struct drm_mode_create_dumb *args)
+{
+ int ret;
+ struct drm_gem_object *gobj;
+ u32 handle;
+
+ LogFunc(("vboxvideo: %d: args->width=%u, args->height=%u, args->bpp=%u\n",
+ __LINE__, (unsigned)args->width, (unsigned)args->height,
+ (unsigned)args->bpp));
+ args->pitch = args->width * ((args->bpp + 7) / 8);
+ args->size = args->pitch * args->height;
+
+ ret = vbox_gem_create(dev, args->size, false,
+ &gobj);
+ if (ret)
+ return ret;
+
+ ret = drm_gem_handle_create(file, gobj, &handle);
+ drm_gem_object_unreference_unlocked(gobj);
+ if (ret)
+ return ret;
+
+ args->handle = handle;
+ LogFunc(("vboxvideo: %d: args->handle=%u\n", __LINE__,
+ (unsigned)args->handle));
+ return 0;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0) && !defined(RHEL_73)
+int vbox_dumb_destroy(struct drm_file *file,
+ struct drm_device *dev,
+ uint32_t handle)
+{
+ LogFunc(("vboxvideo: %d: dev=%p, handle=%u\n", __LINE__, dev,
+ (unsigned)handle));
+ return drm_gem_handle_delete(file, handle);
+}
+#endif
+
+static void vbox_bo_unref(struct vbox_bo **bo)
+{
+ struct ttm_buffer_object *tbo;
+
+ if ((*bo) == NULL)
+ return;
+
+ LogFunc(("vboxvideo: %d: bo=%p\n", __LINE__, bo));
+ tbo = &((*bo)->bo);
+ ttm_bo_unref(&tbo);
+ if (tbo == NULL)
+ *bo = NULL;
+
+}
+void vbox_gem_free_object(struct drm_gem_object *obj)
+{
+ struct vbox_bo *vbox_bo = gem_to_vbox_bo(obj);
+
+ LogFunc(("vboxvideo: %d: vbox_bo=%p\n", __LINE__, vbox_bo));
+ vbox_bo_unref(&vbox_bo);
+}
+
+
+static inline u64 vbox_bo_mmap_offset(struct vbox_bo *bo)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0) && !defined(RHEL_73)
+ return bo->bo.addr_space_offset;
+#else
+ return drm_vma_node_offset_addr(&bo->bo.vma_node);
+#endif
+}
+int
+vbox_dumb_mmap_offset(struct drm_file *file,
+ struct drm_device *dev,
+ uint32_t handle,
+ uint64_t *offset)
+{
+ struct drm_gem_object *obj;
+ int ret;
+ struct vbox_bo *bo;
+
+ LogFunc(("vboxvideo: %d: dev=%p, handle=%u\n", __LINE__,
+ dev, (unsigned)handle));
+ mutex_lock(&dev->struct_mutex);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) || defined(RHEL_74)
+ obj = drm_gem_object_lookup(file, handle);
+#else
+ obj = drm_gem_object_lookup(dev, file, handle);
+#endif
+ if (obj == NULL) {
+ ret = -ENOENT;
+ goto out_unlock;
+ }
+
+ bo = gem_to_vbox_bo(obj);
+ *offset = vbox_bo_mmap_offset(bo);
+
+ drm_gem_object_unreference(obj);
+ ret = 0;
+ LogFunc(("vboxvideo: %d: bo=%p, *offset=%llu\n", __LINE__,
+ bo, (unsigned long long)*offset));
+out_unlock:
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
+
+}
--- /dev/null
+/* $Id: vbox_mode.c $ */
+/** @file
+ * VirtualBox Additions Linux kernel video driver
+ */
+
+/*
+ * Copyright (C) 2013-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on
+ * ast_mode.c
+ * with the following copyright and permission notice:
+ *
+ * Copyright 2012 Red Hat Inc.
+ * Parts based on xf86-video-ast
+ * Copyright (c) 2005 ASPEED Technology Inc.
+ *
+ * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors: Dave Airlie <airlied@redhat.com>
+ */
+#include "vbox_drv.h"
+
+#include <VBox/VBoxVideo.h>
+
+#include <linux/export.h>
+#include <drm/drm_crtc_helper.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0) || defined(RHEL_73)
+# include <drm/drm_plane_helper.h>
+#endif
+
+static int vbox_cursor_set2(struct drm_crtc *crtc, struct drm_file *file_priv,
+ uint32_t handle, uint32_t width, uint32_t height,
+ int32_t hot_x, int32_t hot_y);
+static int vbox_cursor_move(struct drm_crtc *crtc, int x, int y);
+
+/** Set a graphics mode. Poke any required values into registers, do an HGSMI
+ * mode set and tell the host we support advanced graphics functions.
+ */
+static void vbox_do_modeset(struct drm_crtc *crtc,
+ const struct drm_display_mode *mode)
+{
+ struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
+ struct vbox_private *vbox;
+ int width, height, bpp, pitch;
+ unsigned crtc_id;
+ uint16_t flags;
+
+ LogFunc(("vboxvideo: %d: vbox_crtc=%p, CRTC_FB(crtc)=%p\n", __LINE__,
+ vbox_crtc, CRTC_FB(crtc)));
+ vbox = crtc->dev->dev_private;
+ width = mode->hdisplay ? mode->hdisplay : 640;
+ height = mode->vdisplay ? mode->vdisplay : 480;
+ crtc_id = vbox_crtc->crtc_id;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+ bpp = crtc->enabled ? CRTC_FB(crtc)->format->cpp[0] * 8 : 32;
+ pitch = crtc->enabled ? CRTC_FB(crtc)->pitches[0] : width * bpp / 8;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
+ bpp = crtc->enabled ? CRTC_FB(crtc)->bits_per_pixel : 32;
+ pitch = crtc->enabled ? CRTC_FB(crtc)->pitches[0] : width * bpp / 8;
+#else
+ bpp = crtc->enabled ? CRTC_FB(crtc)->bits_per_pixel : 32;
+ pitch = crtc->enabled ? CRTC_FB(crtc)->pitch : width * bpp / 8;
+#endif
+ /* This is the old way of setting graphics modes. It assumed one screen
+ * and a frame-buffer at the start of video RAM. On older versions of
+ * VirtualBox, certain parts of the code still assume that the first
+ * screen is programmed this way, so try to fake it. */
+ if ( vbox_crtc->crtc_id == 0
+ && crtc->enabled
+ && vbox_crtc->fb_offset / pitch < 0xffff - crtc->y
+ && vbox_crtc->fb_offset % (bpp / 8) == 0)
+ VBoxVideoSetModeRegisters(width, height, pitch * 8 / bpp,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+ CRTC_FB(crtc)->format->cpp[0] * 8,
+#else
+ CRTC_FB(crtc)->bits_per_pixel,
+#endif
+ 0,
+ vbox_crtc->fb_offset % pitch / bpp * 8 + crtc->x,
+ vbox_crtc->fb_offset / pitch + crtc->y);
+ flags = VBVA_SCREEN_F_ACTIVE;
+ flags |= (crtc->enabled && !vbox_crtc->blanked ? 0 : VBVA_SCREEN_F_BLANK);
+ flags |= (vbox_crtc->disconnected ? VBVA_SCREEN_F_DISABLED : 0);
+ VBoxHGSMIProcessDisplayInfo(&vbox->submit_info, vbox_crtc->crtc_id,
+ crtc->x, crtc->y,
+ crtc->x * bpp / 8 + crtc->y * pitch,
+ pitch, width, height,
+ vbox_crtc->blanked ? 0 : bpp, flags);
+ LogFunc(("vboxvideo: %d\n", __LINE__));
+}
+
+static int vbox_set_view(struct drm_crtc *crtc)
+{
+ struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
+ struct vbox_private *vbox = crtc->dev->dev_private;
+ void *p;
+
+ LogFunc(("vboxvideo: %d: vbox_crtc=%p\n", __LINE__, vbox_crtc));
+ /* Tell the host about the view. This design originally targeted the
+ * Windows XP driver architecture and assumed that each screen would have
+ * a dedicated frame buffer with the command buffer following it, the whole
+ * being a "view". The host works out which screen a command buffer belongs
+ * to by checking whether it is in the first view, then whether it is in the
+ * second and so on. The first match wins. We cheat around this by making
+ * the first view be the managed memory plus the first command buffer, the
+ * second the same plus the second buffer and so on. */
+ p = VBoxHGSMIBufferAlloc(&vbox->submit_info, sizeof(VBVAINFOVIEW), HGSMI_CH_VBVA,
+ VBVA_INFO_VIEW);
+ if (p)
+ {
+ VBVAINFOVIEW *pInfo = (VBVAINFOVIEW *)p;
+ pInfo->u32ViewIndex = vbox_crtc->crtc_id;
+ pInfo->u32ViewOffset = vbox_crtc->fb_offset;
+ pInfo->u32ViewSize = vbox->available_vram_size - vbox_crtc->fb_offset
+ + vbox_crtc->crtc_id * VBVA_MIN_BUFFER_SIZE;
+ pInfo->u32MaxScreenSize = vbox->available_vram_size - vbox_crtc->fb_offset;
+ VBoxHGSMIBufferSubmit(&vbox->submit_info, p);
+ VBoxHGSMIBufferFree(&vbox->submit_info, p);
+ }
+ else
+ return -ENOMEM;
+ LogFunc(("vboxvideo: %d: p=%p\n", __LINE__, p));
+ return 0;
+}
+
+static void vbox_crtc_load_lut(struct drm_crtc *crtc)
+{
+
+}
+
+static void vbox_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+ struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
+ struct vbox_private *vbox = crtc->dev->dev_private;
+
+ LogFunc(("vboxvideo: %d: vbox_crtc=%p, mode=%d\n", __LINE__, vbox_crtc,
+ mode));
+ switch (mode) {
+ case DRM_MODE_DPMS_ON:
+ vbox_crtc->blanked = false;
+ break;
+ case DRM_MODE_DPMS_STANDBY:
+ case DRM_MODE_DPMS_SUSPEND:
+ case DRM_MODE_DPMS_OFF:
+ vbox_crtc->blanked = true;
+ break;
+ }
+ mutex_lock(&vbox->hw_mutex);
+ vbox_do_modeset(crtc, &crtc->hwmode);
+ mutex_unlock(&vbox->hw_mutex);
+ LogFunc(("vboxvideo: %d\n", __LINE__));
+}
+
+static bool vbox_crtc_mode_fixup(struct drm_crtc *crtc,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+/* We move buffers which are not in active use out of VRAM to save memory. */
+static int vbox_crtc_do_set_base(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ int x, int y, int atomic)
+{
+ struct vbox_private *vbox = crtc->dev->dev_private;
+ struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
+ struct drm_gem_object *obj;
+ struct vbox_framebuffer *vbox_fb;
+ struct vbox_bo *bo;
+ int ret;
+ u64 gpu_addr;
+
+ LogFunc(("vboxvideo: %d: fb=%p, vbox_crtc=%p\n", __LINE__, fb, vbox_crtc));
+ /* push the previous fb to system ram */
+ if (!atomic && fb) {
+ vbox_fb = to_vbox_framebuffer(fb);
+ obj = vbox_fb->obj;
+ bo = gem_to_vbox_bo(obj);
+ ret = vbox_bo_reserve(bo, false);
+ if (ret)
+ return ret;
+ vbox_bo_push_sysram(bo);
+ vbox_bo_unreserve(bo);
+ }
+
+ vbox_fb = to_vbox_framebuffer(CRTC_FB(crtc));
+ obj = vbox_fb->obj;
+ bo = gem_to_vbox_bo(obj);
+
+ ret = vbox_bo_reserve(bo, false);
+ if (ret)
+ return ret;
+
+ ret = vbox_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
+ if (ret) {
+ vbox_bo_unreserve(bo);
+ return ret;
+ }
+
+ if (&vbox->fbdev->afb == vbox_fb) {
+ /* if pushing console in kmap it */
+ ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
+ if (ret)
+ DRM_ERROR("failed to kmap fbcon\n");
+ else
+ vbox_fbdev_set_base(vbox, gpu_addr);
+ }
+ vbox_bo_unreserve(bo);
+
+ /* vbox_set_start_address_crt1(crtc, (u32)gpu_addr); */
+ vbox_crtc->fb_offset = gpu_addr;
+ if (vbox_crtc->crtc_id == 0) {
+ vbox->input_mapping_width = CRTC_FB(crtc)->width;
+ vbox->input_mapping_height = CRTC_FB(crtc)->height;
+ }
+ LogFunc(("vboxvideo: %d: vbox_fb=%p, obj=%p, bo=%p, gpu_addr=%u\n",
+ __LINE__, vbox_fb, obj, bo, (unsigned)gpu_addr));
+ return 0;
+}
+
+static int vbox_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
+ struct drm_framebuffer *old_fb)
+{
+ LogFunc(("vboxvideo: %d\n", __LINE__));
+ return vbox_crtc_do_set_base(crtc, old_fb, x, y, 0);
+}
+
+static int vbox_crtc_mode_set(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode,
+ int x, int y,
+ struct drm_framebuffer *old_fb)
+{
+ struct vbox_private *vbox = crtc->dev->dev_private;
+ int rc = 0;
+
+ LogFunc(("vboxvideo: %d: vbox=%p\n", __LINE__, vbox));
+ vbox_crtc_mode_set_base(crtc, x, y, old_fb);
+ mutex_lock(&vbox->hw_mutex);
+ rc = vbox_set_view(crtc);
+ if (!rc)
+ vbox_do_modeset(crtc, mode);
+ /* Note that the input mapping is always relative to the first screen. */
+ VBoxHGSMIUpdateInputMapping(&vbox->submit_info, 0, 0,
+ vbox->input_mapping_width,
+ vbox->input_mapping_height);
+ mutex_unlock(&vbox->hw_mutex);
+ LogFunc(("vboxvideo: %d\n", __LINE__));
+ return rc;
+}
+
+static void vbox_crtc_disable(struct drm_crtc *crtc)
+{
+
+}
+
+static void vbox_crtc_prepare(struct drm_crtc *crtc)
+{
+
+}
+
+static void vbox_crtc_commit(struct drm_crtc *crtc)
+{
+
+}
+
+
+static const struct drm_crtc_helper_funcs vbox_crtc_helper_funcs = {
+ .dpms = vbox_crtc_dpms,
+ .mode_fixup = vbox_crtc_mode_fixup,
+ .mode_set = vbox_crtc_mode_set,
+ /* .mode_set_base = vbox_crtc_mode_set_base, */
+ .disable = vbox_crtc_disable,
+ .load_lut = vbox_crtc_load_lut,
+ .prepare = vbox_crtc_prepare,
+ .commit = vbox_crtc_commit,
+
+};
+
+static void vbox_crtc_reset(struct drm_crtc *crtc)
+{
+
+}
+
+
+static void vbox_crtc_destroy(struct drm_crtc *crtc)
+{
+ drm_crtc_cleanup(crtc);
+ kfree(crtc);
+}
+
+static const struct drm_crtc_funcs vbox_crtc_funcs = {
+ .cursor_move = vbox_cursor_move,
+ .cursor_set2 = vbox_cursor_set2,
+ .reset = vbox_crtc_reset,
+ .set_config = drm_crtc_helper_set_config,
+ /* .gamma_set = vbox_crtc_gamma_set, */
+ .destroy = vbox_crtc_destroy,
+};
+
+static struct vbox_crtc *vbox_crtc_init(struct drm_device *dev, unsigned i)
+{
+ struct vbox_crtc *vbox_crtc;
+
+ LogFunc(("vboxvideo: %d\n", __LINE__));
+ vbox_crtc = kzalloc(sizeof(struct vbox_crtc), GFP_KERNEL);
+ if (!vbox_crtc)
+ return NULL;
+ vbox_crtc->crtc_id = i;
+
+ drm_crtc_init(dev, &vbox_crtc->base, &vbox_crtc_funcs);
+ drm_mode_crtc_set_gamma_size(&vbox_crtc->base, 256);
+ drm_crtc_helper_add(&vbox_crtc->base, &vbox_crtc_helper_funcs);
+ LogFunc(("vboxvideo: %d: crtc=%p\n", __LINE__, vbox_crtc));
+
+ return vbox_crtc;
+}
+
+static void vbox_encoder_destroy(struct drm_encoder *encoder)
+{
+ LogFunc(("vboxvideo: %d: encoder=%p\n", __LINE__, encoder));
+ drm_encoder_cleanup(encoder);
+ kfree(encoder);
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) && !defined(RHEL_73)
+static struct drm_encoder *drm_encoder_find(struct drm_device *dev, uint32_t id)
+{
+ struct drm_mode_object *mo;
+ mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_ENCODER);
+ return mo ? obj_to_encoder(mo) : NULL;
+}
+#endif
+
+static struct drm_encoder *vbox_best_single_encoder(struct drm_connector *connector)
+{
+ int enc_id = connector->encoder_ids[0];
+
+ LogFunc(("vboxvideo: %d: connector=%p\n", __LINE__, connector));
+ /* pick the encoder ids */
+ if (enc_id)
+ return drm_encoder_find(connector->dev, enc_id);
+ LogFunc(("vboxvideo: %d\n", __LINE__));
+ return NULL;
+}
+
+
+static const struct drm_encoder_funcs vbox_enc_funcs = {
+ .destroy = vbox_encoder_destroy,
+};
+
+static void vbox_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+
+}
+
+static bool vbox_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static void vbox_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+}
+
+static void vbox_encoder_prepare(struct drm_encoder *encoder)
+{
+
+}
+
+static void vbox_encoder_commit(struct drm_encoder *encoder)
+{
+
+}
+
+
+static const struct drm_encoder_helper_funcs vbox_enc_helper_funcs = {
+ .dpms = vbox_encoder_dpms,
+ .mode_fixup = vbox_mode_fixup,
+ .prepare = vbox_encoder_prepare,
+ .commit = vbox_encoder_commit,
+ .mode_set = vbox_encoder_mode_set,
+};
+
+static struct drm_encoder *vbox_encoder_init(struct drm_device *dev, unsigned i)
+{
+ struct vbox_encoder *vbox_encoder;
+
+ LogFunc(("vboxvideo: %d: dev=%d\n", __LINE__));
+ vbox_encoder = kzalloc(sizeof(struct vbox_encoder), GFP_KERNEL);
+ if (!vbox_encoder)
+ return NULL;
+
+ drm_encoder_init(dev, &vbox_encoder->base, &vbox_enc_funcs,
+ DRM_MODE_ENCODER_DAC
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0) || defined(RHEL_73)
+ , NULL
+#endif
+ );
+ drm_encoder_helper_add(&vbox_encoder->base, &vbox_enc_helper_funcs);
+
+ vbox_encoder->base.possible_crtcs = 1 << i;
+ LogFunc(("vboxvideo: %d: vbox_encoder=%p\n", __LINE__, vbox_encoder));
+ return &vbox_encoder->base;
+}
+
+/** Generate EDID data with a mode-unique serial number for the virtual
+ * monitor to try to persuade Unity that different modes correspond to
+ * different monitors and it should not try to force the same resolution on
+ * them. */
+static void vbox_set_edid(struct drm_connector *connector, int width,
+ int height)
+{
+ enum { EDID_SIZE = 128 };
+ unsigned char edid[EDID_SIZE] = {
+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, /* header */
+ 0x58, 0x58, /* manufacturer (VBX) */
+ 0x00, 0x00, /* product code */
+ 0x00, 0x00,0x00, 0x00, /* serial number goes here */
+ 0x01, /* week of manufacture */
+ 0x00, /* year of manufacture */
+ 0x01, 0x03, /* EDID version */
+ 0x80, /* capabilities - digital */
+ 0x00, /* horiz. res in cm, zero for projectors */
+ 0x00, /* vert. res in cm */
+ 0x78, /* display gamma (120 == 2.2). */
+ 0xEE, /* features (standby, suspend, off, RGB, standard colour space,
+ * preferred timing mode) */
+ 0xEE, 0x91, 0xA3, 0x54, 0x4C, 0x99, 0x26, 0x0F, 0x50, 0x54,
+ /* chromaticity for standard colour space. */
+ 0x00, 0x00, 0x00, /* no default timings */
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, /* no standard timings */
+ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x00, 0x02, 0x02, 0x02, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* descriptor block 1 goes here */
+ 0x00, 0x00, 0x00, 0xFD, 0x00, /* descriptor block 2, monitor ranges */
+ 0x00, 0xC8, 0x00, 0xC8, 0x64, 0x00, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, /* 0-200Hz vertical, 0-200KHz horizontal, 1000MHz pixel clock */
+ 0x00, 0x00, 0x00, 0xFC, 0x00, /* descriptor block 3, monitor name */
+ 'V', 'B', 'O', 'X', ' ', 'm', 'o', 'n', 'i', 't', 'o', 'r', '\n',
+ 0x00, 0x00, 0x00, 0x10, 0x00, /* descriptor block 4: dummy data */
+ 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20,
+ 0x00, /* number of extensions */
+ 0x00 /* checksum goes here */
+ };
+ int clock = (width + 6) * (height + 6) * 60 / 10000;
+ unsigned i;
+ unsigned sum = 0;
+
+ edid[12] = width & 0xff;
+ edid[13] = width >> 8;
+ edid[14] = height & 0xff;
+ edid[15] = height >> 8;
+ edid[54] = clock & 0xff;
+ edid[55] = clock >> 8;
+ edid[56] = width & 0xff;
+ edid[58] = (width >> 4) & 0xf0;
+ edid[59] = height & 0xff;
+ edid[61] = (height >> 4) & 0xf0;
+ for (i = 0; i < EDID_SIZE - 1; ++i)
+ sum += edid[i];
+ edid[EDID_SIZE - 1] = (0x100 - (sum & 0xFF)) & 0xFF;
+ drm_mode_connector_update_edid_property(connector, (struct edid *)edid);
+}
+
+static int vbox_get_modes(struct drm_connector *connector)
+{
+ struct vbox_connector *vbox_connector = NULL;
+ struct drm_display_mode *mode = NULL;
+ struct vbox_private *vbox = NULL;
+ unsigned num_modes = 0;
+ int preferred_width, preferred_height;
+
+ LogFunc(("vboxvideo: %d: connector=%p\n", __LINE__, connector));
+ vbox_connector = to_vbox_connector(connector);
+ vbox = connector->dev->dev_private;
+ /* Heuristic: we do not want to tell the host that we support dynamic
+ * resizing unless we feel confident that the user space client using
+ * the video driver can handle hot-plug events. So the first time modes
+ * are queried after a "master" switch we tell the host that we do not,
+ * and immediately after we send the client a hot-plug notification as
+ * a test to see if they will respond and query again.
+ * That is also the reason why capabilities are reported to the host at
+ * this place in the code rather than elsewhere.
+ * We need to report the flags location before reporting the IRQ
+ * capability. */
+ VBoxHGSMIReportFlagsLocation(&vbox->submit_info, vbox->vram_map_start
+ + vbox->host_flags_offset);
+ if (vbox_connector->vbox_crtc->crtc_id == 0)
+ vbox_report_caps(vbox);
+ if (!vbox->initial_mode_queried) {
+ if (vbox_connector->vbox_crtc->crtc_id == 0) {
+ vbox->initial_mode_queried = true;
+ vbox_report_hotplug(vbox);
+ }
+ return drm_add_modes_noedid(connector, 800, 600);
+ }
+ num_modes = drm_add_modes_noedid(connector, 2560, 1600);
+ preferred_width = vbox_connector->mode_hint.width ? vbox_connector->mode_hint.width : 1024;
+ preferred_height = vbox_connector->mode_hint.height ? vbox_connector->mode_hint.height : 768;
+ mode = drm_cvt_mode(connector->dev, preferred_width, preferred_height, 60, false,
+ false, false);
+ if (mode)
+ {
+ mode->type |= DRM_MODE_TYPE_PREFERRED;
+ drm_mode_probed_add(connector, mode);
+ ++num_modes;
+ }
+ vbox_set_edid(connector, preferred_width, preferred_height);
+ return num_modes;
+}
+
+static int vbox_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ return MODE_OK;
+}
+
+static void vbox_connector_destroy(struct drm_connector *connector)
+{
+ struct vbox_connector *vbox_connector = NULL;
+
+ LogFunc(("vboxvideo: %d: connector=%p\n", __LINE__, connector));
+ vbox_connector = to_vbox_connector(connector);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) && !defined(RHEL_73)
+ drm_sysfs_connector_remove(connector);
+#else
+ drm_connector_unregister(connector);
+#endif
+ drm_connector_cleanup(connector);
+ kfree(connector);
+}
+
+static enum drm_connector_status
+vbox_connector_detect(struct drm_connector *connector, bool force)
+{
+ struct vbox_connector *vbox_connector = NULL;
+
+ (void) force;
+ LogFunc(("vboxvideo: %d: connector=%p\n", __LINE__, connector));
+ vbox_connector = to_vbox_connector(connector);
+ return vbox_connector->mode_hint.disconnected ?
+ connector_status_disconnected : connector_status_connected;
+}
+
+static int vbox_fill_modes(struct drm_connector *connector, uint32_t max_x, uint32_t max_y)
+{
+ struct vbox_connector *vbox_connector;
+ struct drm_device *dev;
+ struct drm_display_mode *mode, *iterator;
+
+ LogFunc(("vboxvideo: %d: connector=%p, max_x=%lu, max_y = %lu\n", __LINE__,
+ connector, (unsigned long)max_x, (unsigned long)max_y));
+ vbox_connector = to_vbox_connector(connector);
+ dev = vbox_connector->base.dev;
+ list_for_each_entry_safe(mode, iterator, &connector->modes, head)
+ {
+ list_del(&mode->head);
+ drm_mode_destroy(dev, mode);
+ }
+ return drm_helper_probe_single_connector_modes(connector, max_x, max_y);
+}
+
+static const struct drm_connector_helper_funcs vbox_connector_helper_funcs = {
+ .mode_valid = vbox_mode_valid,
+ .get_modes = vbox_get_modes,
+ .best_encoder = vbox_best_single_encoder,
+};
+
+static const struct drm_connector_funcs vbox_connector_funcs = {
+ .dpms = drm_helper_connector_dpms,
+ .detect = vbox_connector_detect,
+ .fill_modes = vbox_fill_modes,
+ .destroy = vbox_connector_destroy,
+};
+
+static int vbox_connector_init(struct drm_device *dev,
+ struct vbox_crtc *vbox_crtc,
+ struct drm_encoder *encoder)
+{
+ struct vbox_connector *vbox_connector;
+ struct drm_connector *connector;
+
+ LogFunc(("vboxvideo: %d: dev=%p, encoder=%p\n", __LINE__, dev,
+ encoder));
+ vbox_connector = kzalloc(sizeof(struct vbox_connector), GFP_KERNEL);
+ if (!vbox_connector)
+ return -ENOMEM;
+
+ connector = &vbox_connector->base;
+ vbox_connector->vbox_crtc = vbox_crtc;
+
+ drm_connector_init(dev, connector, &vbox_connector_funcs,
+ DRM_MODE_CONNECTOR_VGA);
+ drm_connector_helper_add(connector, &vbox_connector_helper_funcs);
+
+ connector->interlace_allowed = 0;
+ connector->doublescan_allowed = 0;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) || defined(RHEL_73)
+ drm_mode_create_suggested_offset_properties(dev);
+ drm_object_attach_property(&connector->base,
+ dev->mode_config.suggested_x_property, 0);
+ drm_object_attach_property(&connector->base,
+ dev->mode_config.suggested_y_property, 0);
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) && !defined(RHEL_73)
+ drm_sysfs_connector_add(connector);
+#else
+ drm_connector_register(connector);
+#endif
+
+ drm_mode_connector_attach_encoder(connector, encoder);
+
+ LogFunc(("vboxvideo: %d: connector=%p\n", __LINE__, connector));
+ return 0;
+}
+
+int vbox_mode_init(struct drm_device *dev)
+{
+ struct vbox_private *vbox = dev->dev_private;
+ struct drm_encoder *encoder;
+ struct vbox_crtc *vbox_crtc;
+ unsigned i;
+ /* vbox_cursor_init(dev); */
+ LogFunc(("vboxvideo: %d: dev=%p\n", __LINE__, dev));
+ for (i = 0; i < vbox->num_crtcs; ++i)
+ {
+ vbox_crtc = vbox_crtc_init(dev, i);
+ if (!vbox_crtc)
+ return -ENOMEM;
+ encoder = vbox_encoder_init(dev, i);
+ if (!encoder)
+ return -ENOMEM;
+ vbox_connector_init(dev, vbox_crtc, encoder);
+ }
+ return 0;
+}
+
+void vbox_mode_fini(struct drm_device *dev)
+{
+ /* vbox_cursor_fini(dev); */
+}
+
+
+/** Copy the ARGB image and generate the mask, which is needed in case the host
+ * does not support ARGB cursors. The mask is a 1BPP bitmap with the bit set
+ * if the corresponding alpha value in the ARGB image is greater than 0xF0. */
+static void copy_cursor_image(u8 *src, u8 *dst, int width, int height,
+ size_t mask_size)
+{
+ unsigned i, j;
+ size_t line_size = (width + 7) / 8;
+
+ memcpy(dst + mask_size, src, width * height * 4);
+ for (i = 0; i < height; ++i)
+ for (j = 0; j < width; ++j)
+ if (((uint32_t *)src)[i * width + j] > 0xf0000000)
+ dst[i * line_size + j / 8] |= (0x80 >> (j % 8));
+}
+
+static int vbox_cursor_set2(struct drm_crtc *crtc, struct drm_file *file_priv,
+ uint32_t handle, uint32_t width, uint32_t height,
+ int32_t hot_x, int32_t hot_y)
+{
+ struct vbox_private *vbox = crtc->dev->dev_private;
+ struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
+ struct drm_gem_object *obj;
+ struct vbox_bo *bo;
+ int ret, rc;
+ struct ttm_bo_kmap_obj uobj_map;
+ u8 *src;
+ u8 *dst = NULL;
+ u32 caps = 0;
+ size_t data_size, mask_size;
+ bool src_isiomem;
+
+ /* Re-set this regularly as in 5.0.20 and earlier the information was lost
+ * on save and restore. */
+ VBoxHGSMIUpdateInputMapping(&vbox->submit_info, 0, 0,
+ vbox->input_mapping_width,
+ vbox->input_mapping_height);
+ if (!handle) {
+ bool cursor_enabled = false;
+ struct drm_crtc *crtci;
+
+ /* Hide cursor. */
+ vbox_crtc->cursor_enabled = false;
+ list_for_each_entry(crtci, &vbox->dev->mode_config.crtc_list, head)
+ if (to_vbox_crtc(crtci)->cursor_enabled)
+ cursor_enabled = true;
+ if (!cursor_enabled)
+ VBoxHGSMIUpdatePointerShape(&vbox->submit_info, 0, 0, 0, 0, 0, NULL, 0);
+ return 0;
+ }
+ vbox_crtc->cursor_enabled = true;
+ if ( width > VBOX_MAX_CURSOR_WIDTH || height > VBOX_MAX_CURSOR_HEIGHT
+ || width == 0 || height == 0)
+ return -EINVAL;
+ rc = VBoxQueryConfHGSMI(&vbox->submit_info,
+ VBOX_VBVA_CONF32_CURSOR_CAPABILITIES, &caps);
+ ret = -RTErrConvertToErrno(rc);
+ if (ret)
+ return ret;
+ if ( caps & VMMDEV_MOUSE_HOST_CANNOT_HWPOINTER
+ || !(caps & VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE))
+ /* -EINVAL means cursor_set2() not supported, -EAGAIN means
+ * retry at once. */
+ return -EBUSY;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) || defined(RHEL_74)
+ obj = drm_gem_object_lookup(file_priv, handle);
+#else
+ obj = drm_gem_object_lookup(crtc->dev, file_priv, handle);
+#endif
+ if (obj)
+ {
+ bo = gem_to_vbox_bo(obj);
+ ret = vbox_bo_reserve(bo, false);
+ if (!ret)
+ {
+ /* The mask must be calculated based on the alpha channel, one bit
+ * per ARGB word, and must be 32-bit padded. */
+ mask_size = ((width + 7) / 8 * height + 3) & ~3;
+ data_size = width * height * 4 + mask_size;
+ vbox->cursor_hot_x = min((uint32_t)max(hot_x, 0), width);
+ vbox->cursor_hot_y = min((uint32_t)max(hot_y, 0), height);
+ vbox->cursor_width = width;
+ vbox->cursor_height = height;
+ vbox->cursor_data_size = data_size;
+ dst = vbox->cursor_data;
+ ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &uobj_map);
+ if (!ret)
+ {
+ src = ttm_kmap_obj_virtual(&uobj_map, &src_isiomem);
+ if (!src_isiomem)
+ {
+ uint32_t flags = VBOX_MOUSE_POINTER_VISIBLE
+ | VBOX_MOUSE_POINTER_SHAPE
+ | VBOX_MOUSE_POINTER_ALPHA;
+ copy_cursor_image(src, dst, width, height, mask_size);
+ rc = VBoxHGSMIUpdatePointerShape(&vbox->submit_info, flags,
+ vbox->cursor_hot_x,
+ vbox->cursor_hot_y,
+ width, height, dst,
+ data_size);
+ ret = -RTErrConvertToErrno(rc);
+ }
+ else
+ DRM_ERROR("src cursor bo should be in main memory\n");
+ ttm_bo_kunmap(&uobj_map);
+ }
+ else
+ vbox->cursor_data_size = 0;
+ vbox_bo_unreserve(bo);
+ }
+ drm_gem_object_unreference_unlocked(obj);
+ }
+ else
+ {
+ DRM_ERROR("Cannot find cursor object %x for crtc\n", handle);
+ ret = -ENOENT;
+ }
+ return ret;
+}
+
+static int vbox_cursor_move(struct drm_crtc *crtc,
+ int x, int y)
+{
+ struct vbox_private *vbox = crtc->dev->dev_private;
+ uint32_t flags = VBOX_MOUSE_POINTER_VISIBLE
+ | VBOX_MOUSE_POINTER_SHAPE
+ | VBOX_MOUSE_POINTER_ALPHA;
+ uint32_t host_x, host_y;
+ uint32_t hot_x = 0;
+ uint32_t hot_y = 0;
+ int rc;
+
+ /* We compare these to unsigned later and don't need to handle negative. */
+ if (x + crtc->x < 0 || y + crtc->y < 0 || vbox->cursor_data_size == 0)
+ return 0;
+ rc = VBoxHGSMICursorPosition(&vbox->submit_info, true, x + crtc->x,
+ y + crtc->y, &host_x, &host_y);
+ /* Work around a bug after save and restore in 5.0.20 and earlier. */
+ if (RT_FAILURE(rc) || (host_x == 0 && host_y == 0))
+ return -RTErrConvertToErrno(rc);
+ if (x + crtc->x < host_x)
+ hot_x = min(host_x - x - crtc->x, vbox->cursor_width);
+ if (y + crtc->y < host_y)
+ hot_y = min(host_y - y - crtc->y, vbox->cursor_height);
+ if (hot_x == vbox->cursor_hot_x && hot_y == vbox->cursor_hot_y)
+ return 0;
+ vbox->cursor_hot_x = hot_x;
+ vbox->cursor_hot_y = hot_y;
+ rc = VBoxHGSMIUpdatePointerShape(&vbox->submit_info, flags, hot_x, hot_y,
+ vbox->cursor_width, vbox->cursor_height,
+ vbox->cursor_data,
+ vbox->cursor_data_size);
+ return -RTErrConvertToErrno(rc);
+}
--- /dev/null
+/*
+ * Copyright (C) 2017 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+
+ * Copyright 2017 Canonical
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: Andreas Pokorny
+ */
+
+#include "vbox_drv.h"
+
+/* Based on qxl_prime.c:
+ * Empty Implementations as there should not be any other driver for a virtual
+ * device that might share buffers with vboxvideo */
+
+int vbox_gem_prime_pin(struct drm_gem_object *obj)
+{
+ WARN_ONCE(1, "not implemented");
+ return -ENOSYS;
+}
+
+void vbox_gem_prime_unpin(struct drm_gem_object *obj)
+{
+ WARN_ONCE(1, "not implemented");
+}
+
+
+struct sg_table *vbox_gem_prime_get_sg_table(struct drm_gem_object *obj)
+{
+ WARN_ONCE(1, "not implemented");
+ return ERR_PTR(-ENOSYS);
+}
+
+struct drm_gem_object *vbox_gem_prime_import_sg_table(
+ struct drm_device *dev,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0) && !defined(RHEL_73)
+ size_t size,
+#else
+ struct dma_buf_attachment *attach,
+#endif
+ struct sg_table *table)
+{
+ WARN_ONCE(1, "not implemented");
+ return ERR_PTR(-ENOSYS);
+}
+
+void *vbox_gem_prime_vmap(struct drm_gem_object *obj)
+{
+ WARN_ONCE(1, "not implemented");
+ return ERR_PTR(-ENOSYS);
+}
+
+void vbox_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
+{
+ WARN_ONCE(1, "not implemented");
+}
+
+int vbox_gem_prime_mmap(struct drm_gem_object *obj,
+ struct vm_area_struct *area)
+{
+ WARN_ONCE(1, "not implemented");
+ return -ENOSYS;
+}
--- /dev/null
+/* $Id: vbox_ttm.c $ */
+/** @file
+ * VirtualBox Additions Linux kernel video driver
+ */
+
+/*
+ * Copyright (C) 2013-2016 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on
+ * ast_ttm.c
+ * with the following copyright and permission notice:
+ *
+ * Copyright 2012 Red Hat Inc.
+ *
+ * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors: Dave Airlie <airlied@redhat.com>
+ */
+#include "vbox_drv.h"
+#include <ttm/ttm_page_alloc.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0) && !defined(RHEL_73)
+# define PLACEMENT_FLAGS(placement) (placement)
+#else
+# define PLACEMENT_FLAGS(placement) (placement).flags
+#endif
+
+static inline struct vbox_private *
+vbox_bdev(struct ttm_bo_device *bd)
+{
+ return container_of(bd, struct vbox_private, ttm.bdev);
+}
+
+static int
+vbox_ttm_mem_global_init(struct drm_global_reference *ref)
+{
+ return ttm_mem_global_init(ref->object);
+}
+
+static void
+vbox_ttm_mem_global_release(struct drm_global_reference *ref)
+{
+ ttm_mem_global_release(ref->object);
+}
+
+/**
+ * Adds the vbox memory manager object/structures to the global memory manager.
+ */
+static int vbox_ttm_global_init(struct vbox_private *vbox)
+{
+ struct drm_global_reference *global_ref;
+ int r;
+
+ global_ref = &vbox->ttm.mem_global_ref;
+ global_ref->global_type = DRM_GLOBAL_TTM_MEM;
+ global_ref->size = sizeof(struct ttm_mem_global);
+ global_ref->init = &vbox_ttm_mem_global_init;
+ global_ref->release = &vbox_ttm_mem_global_release;
+ r = drm_global_item_ref(global_ref);
+ if (r != 0) {
+ DRM_ERROR("Failed setting up TTM memory accounting "
+ "subsystem.\n");
+ return r;
+ }
+
+ vbox->ttm.bo_global_ref.mem_glob =
+ vbox->ttm.mem_global_ref.object;
+ global_ref = &vbox->ttm.bo_global_ref.ref;
+ global_ref->global_type = DRM_GLOBAL_TTM_BO;
+ global_ref->size = sizeof(struct ttm_bo_global);
+ global_ref->init = &ttm_bo_global_init;
+ global_ref->release = &ttm_bo_global_release;
+ r = drm_global_item_ref(global_ref);
+ if (r != 0) {
+ DRM_ERROR("Failed setting up TTM BO subsystem.\n");
+ drm_global_item_unref(&vbox->ttm.mem_global_ref);
+ return r;
+ }
+ return 0;
+}
+
+/**
+ * Removes the vbox memory manager object from the global memory manager.
+ */
+static void
+vbox_ttm_global_release(struct vbox_private *vbox)
+{
+ if (vbox->ttm.mem_global_ref.release == NULL)
+ return;
+
+ drm_global_item_unref(&vbox->ttm.bo_global_ref.ref);
+ drm_global_item_unref(&vbox->ttm.mem_global_ref);
+ vbox->ttm.mem_global_ref.release = NULL;
+}
+
+
+static void vbox_bo_ttm_destroy(struct ttm_buffer_object *tbo)
+{
+ struct vbox_bo *bo;
+
+ bo = container_of(tbo, struct vbox_bo, bo);
+
+ drm_gem_object_release(&bo->gem);
+ kfree(bo);
+}
+
+static bool vbox_ttm_bo_is_vbox_bo(struct ttm_buffer_object *bo)
+{
+ if (bo->destroy == &vbox_bo_ttm_destroy)
+ return true;
+ return false;
+}
+
+static int
+vbox_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
+ struct ttm_mem_type_manager *man)
+{
+ switch (type) {
+ case TTM_PL_SYSTEM:
+ man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
+ man->available_caching = TTM_PL_MASK_CACHING;
+ man->default_caching = TTM_PL_FLAG_CACHED;
+ break;
+ case TTM_PL_VRAM:
+ man->func = &ttm_bo_manager_func;
+ man->flags = TTM_MEMTYPE_FLAG_FIXED |
+ TTM_MEMTYPE_FLAG_MAPPABLE;
+ man->available_caching = TTM_PL_FLAG_UNCACHED |
+ TTM_PL_FLAG_WC;
+ man->default_caching = TTM_PL_FLAG_WC;
+ break;
+ default:
+ DRM_ERROR("Unsupported memory type %u\n", (unsigned)type);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void
+vbox_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
+{
+ struct vbox_bo *vboxbo = vbox_bo(bo);
+
+ if (!vbox_ttm_bo_is_vbox_bo(bo))
+ return;
+
+ vbox_ttm_placement(vboxbo, TTM_PL_FLAG_SYSTEM);
+ *pl = vboxbo->placement;
+}
+
+static int vbox_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp)
+{
+ return 0;
+}
+
+static int vbox_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
+ struct ttm_mem_reg *mem)
+{
+ struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
+ struct vbox_private *vbox = vbox_bdev(bdev);
+
+ mem->bus.addr = NULL;
+ mem->bus.offset = 0;
+ mem->bus.size = mem->num_pages << PAGE_SHIFT;
+ mem->bus.base = 0;
+ mem->bus.is_iomem = false;
+ if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE))
+ return -EINVAL;
+ switch (mem->mem_type) {
+ case TTM_PL_SYSTEM:
+ /* system memory */
+ return 0;
+ case TTM_PL_VRAM:
+ mem->bus.offset = mem->start << PAGE_SHIFT;
+ mem->bus.base = pci_resource_start(vbox->dev->pdev, 0);
+ mem->bus.is_iomem = true;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ return 0;
+}
+
+static void vbox_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
+{
+}
+
+static int vbox_bo_move(struct ttm_buffer_object *bo,
+ bool evict, bool interruptible,
+ bool no_wait_gpu,
+ struct ttm_mem_reg *new_mem)
+{
+ int r;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0) && !defined(RHEL_74)
+ r = ttm_bo_move_memcpy(bo, evict, no_wait_gpu, new_mem);
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) && !defined(RHEL_74)
+ r = ttm_bo_move_memcpy(bo, evict, interruptible, no_wait_gpu, new_mem);
+#else
+ r = ttm_bo_move_memcpy(bo, interruptible, no_wait_gpu, new_mem);
+#endif
+ return r;
+}
+
+
+static void vbox_ttm_backend_destroy(struct ttm_tt *tt)
+{
+ ttm_tt_fini(tt);
+ kfree(tt);
+}
+
+static struct ttm_backend_func vbox_tt_backend_func = {
+ .destroy = &vbox_ttm_backend_destroy,
+};
+
+
+static struct ttm_tt *vbox_ttm_tt_create(struct ttm_bo_device *bdev,
+ unsigned long size, uint32_t page_flags,
+ struct page *dummy_read_page)
+{
+ struct ttm_tt *tt;
+
+ tt = kzalloc(sizeof(struct ttm_tt), GFP_KERNEL);
+ if (tt == NULL)
+ return NULL;
+ tt->func = &vbox_tt_backend_func;
+ if (ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page)) {
+ kfree(tt);
+ return NULL;
+ }
+ return tt;
+}
+
+static int vbox_ttm_tt_populate(struct ttm_tt *ttm)
+{
+ return ttm_pool_populate(ttm);
+}
+
+static void vbox_ttm_tt_unpopulate(struct ttm_tt *ttm)
+{
+ ttm_pool_unpopulate(ttm);
+}
+
+struct ttm_bo_driver vbox_bo_driver = {
+ .ttm_tt_create = vbox_ttm_tt_create,
+ .ttm_tt_populate = vbox_ttm_tt_populate,
+ .ttm_tt_unpopulate = vbox_ttm_tt_unpopulate,
+ .init_mem_type = vbox_bo_init_mem_type,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) || defined(RHEL_74)
+ .eviction_valuable = ttm_bo_eviction_valuable,
+#endif
+ .evict_flags = vbox_bo_evict_flags,
+ .move = vbox_bo_move,
+ .verify_access = vbox_bo_verify_access,
+ .io_mem_reserve = &vbox_ttm_io_mem_reserve,
+ .io_mem_free = &vbox_ttm_io_mem_free,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
+ .io_mem_pfn = ttm_bo_default_io_mem_pfn,
+#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) && LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)) \
+ || defined(RHEL_74)
+ .lru_tail = &ttm_bo_default_lru_tail,
+ .swap_lru_tail = &ttm_bo_default_swap_lru_tail,
+#endif
+};
+
+int vbox_mm_init(struct vbox_private *vbox)
+{
+ int ret;
+ struct drm_device *dev = vbox->dev;
+ struct ttm_bo_device *bdev = &vbox->ttm.bdev;
+
+ ret = vbox_ttm_global_init(vbox);
+ if (ret)
+ return ret;
+
+ ret = ttm_bo_device_init(&vbox->ttm.bdev,
+ vbox->ttm.bo_global_ref.ref.object,
+ &vbox_bo_driver,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) || defined(RHEL_73)
+ dev->anon_inode->i_mapping,
+#endif
+ DRM_FILE_PAGE_OFFSET,
+ true);
+ if (ret) {
+ DRM_ERROR("Error initialising bo driver; %d\n", ret);
+ return ret;
+ }
+
+ ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM,
+ vbox->available_vram_size >> PAGE_SHIFT);
+ if (ret) {
+ DRM_ERROR("Failed ttm VRAM init: %d\n", ret);
+ return ret;
+ }
+
+#ifdef DRM_MTRR_WC
+ vbox->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 0),
+ pci_resource_len(dev->pdev, 0),
+ DRM_MTRR_WC);
+#else
+ vbox->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0),
+ pci_resource_len(dev->pdev, 0));
+#endif
+
+ vbox->ttm.mm_initialised = true;
+ return 0;
+}
+
+void vbox_mm_fini(struct vbox_private *vbox)
+{
+#ifdef DRM_MTRR_WC
+ struct drm_device *dev = vbox->dev;
+#endif
+ if (!vbox->ttm.mm_initialised)
+ return;
+ ttm_bo_device_release(&vbox->ttm.bdev);
+
+ vbox_ttm_global_release(vbox);
+
+#ifdef DRM_MTRR_WC
+ drm_mtrr_del(vbox->fb_mtrr,
+ pci_resource_start(dev->pdev, 0),
+ pci_resource_len(dev->pdev, 0), DRM_MTRR_WC);
+#else
+ arch_phys_wc_del(vbox->fb_mtrr);
+#endif
+}
+
+void vbox_ttm_placement(struct vbox_bo *bo, int domain)
+{
+ u32 c = 0;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0) && !defined(RHEL_73)
+ bo->placement.fpfn = 0;
+ bo->placement.lpfn = 0;
+#else
+ unsigned i;
+#endif
+
+ bo->placement.placement = bo->placements;
+ bo->placement.busy_placement = bo->placements;
+ if (domain & TTM_PL_FLAG_VRAM)
+ PLACEMENT_FLAGS(bo->placements[c++]) = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
+ if (domain & TTM_PL_FLAG_SYSTEM)
+ PLACEMENT_FLAGS(bo->placements[c++]) = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
+ if (!c)
+ PLACEMENT_FLAGS(bo->placements[c++]) = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
+ bo->placement.num_placement = c;
+ bo->placement.num_busy_placement = c;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0) || defined(RHEL_73)
+ for (i = 0; i < c; ++i) {
+ bo->placements[i].fpfn = 0;
+ bo->placements[i].lpfn = 0;
+ }
+#endif
+}
+
+int vbox_bo_create(struct drm_device *dev, int size, int align,
+ uint32_t flags, struct vbox_bo **pvboxbo)
+{
+ struct vbox_private *vbox = dev->dev_private;
+ struct vbox_bo *vboxbo;
+ size_t acc_size;
+ int ret;
+
+ vboxbo = kzalloc(sizeof(struct vbox_bo), GFP_KERNEL);
+ if (!vboxbo)
+ return -ENOMEM;
+
+ ret = drm_gem_object_init(dev, &vboxbo->gem, size);
+ if (ret) {
+ kfree(vboxbo);
+ return ret;
+ }
+
+ vboxbo->bo.bdev = &vbox->ttm.bdev;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0) && !defined(RHEL_73)
+ vboxbo->bo.bdev->dev_mapping = dev->dev_mapping;
+#endif
+
+ vbox_ttm_placement(vboxbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
+
+ acc_size = ttm_bo_dma_acc_size(&vbox->ttm.bdev, size,
+ sizeof(struct vbox_bo));
+
+ ret = ttm_bo_init(&vbox->ttm.bdev, &vboxbo->bo, size,
+ ttm_bo_type_device, &vboxbo->placement,
+ align >> PAGE_SHIFT, false, NULL, acc_size,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0) || defined(RHEL_73)
+ NULL,
+#endif
+ NULL, vbox_bo_ttm_destroy);
+ if (ret)
+ return ret;
+
+ *pvboxbo = vboxbo;
+ return 0;
+}
+
+static inline u64 vbox_bo_gpu_offset(struct vbox_bo *bo)
+{
+ return bo->bo.offset;
+}
+
+int vbox_bo_pin(struct vbox_bo *bo, u32 pl_flag, u64 *gpu_addr)
+{
+ int i, ret;
+
+ if (bo->pin_count) {
+ bo->pin_count++;
+ if (gpu_addr)
+ *gpu_addr = vbox_bo_gpu_offset(bo);
+ return 0;
+ }
+
+ vbox_ttm_placement(bo, pl_flag);
+ for (i = 0; i < bo->placement.num_placement; i++)
+ PLACEMENT_FLAGS(bo->placements[i]) |= TTM_PL_FLAG_NO_EVICT;
+ ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
+ if (ret)
+ return ret;
+
+ bo->pin_count = 1;
+ if (gpu_addr)
+ *gpu_addr = vbox_bo_gpu_offset(bo);
+ return 0;
+}
+
+int vbox_bo_unpin(struct vbox_bo *bo)
+{
+ int i, ret;
+ if (!bo->pin_count) {
+ DRM_ERROR("unpin bad %p\n", bo);
+ return 0;
+ }
+ bo->pin_count--;
+ if (bo->pin_count)
+ return 0;
+
+ for (i = 0; i < bo->placement.num_placement ; i++)
+ PLACEMENT_FLAGS(bo->placements[i]) &= ~TTM_PL_FLAG_NO_EVICT;
+ ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+/* Move a vbox-owned buffer object to system memory if no one else has it
+ * pinned. The caller must have pinned it previously, and this call will
+ * release the caller's pin. */
+int vbox_bo_push_sysram(struct vbox_bo *bo)
+{
+ int i, ret;
+ if (!bo->pin_count) {
+ DRM_ERROR("unpin bad %p\n", bo);
+ return 0;
+ }
+ bo->pin_count--;
+ if (bo->pin_count)
+ return 0;
+
+ if (bo->kmap.virtual)
+ ttm_bo_kunmap(&bo->kmap);
+
+ vbox_ttm_placement(bo, TTM_PL_FLAG_SYSTEM);
+ for (i = 0; i < bo->placement.num_placement ; i++)
+ PLACEMENT_FLAGS(bo->placements[i]) |= TTM_PL_FLAG_NO_EVICT;
+
+ ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
+ if (ret) {
+ DRM_ERROR("pushing to VRAM failed\n");
+ return ret;
+ }
+ return 0;
+}
+
+int vbox_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct drm_file *file_priv;
+ struct vbox_private *vbox;
+
+ if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET))
+ return -EINVAL;
+
+ file_priv = filp->private_data;
+ vbox = file_priv->minor->dev->dev_private;
+ return ttm_bo_mmap(filp, vma, &vbox->ttm.bdev);
+}
--- /dev/null
+#ifndef ___version_generated_h___
+#define ___version_generated_h___
+
+#define VBOX_VERSION_MAJOR 5
+#define VBOX_VERSION_MINOR 1
+#define VBOX_VERSION_BUILD 28
+#define VBOX_VERSION_STRING_RAW "5.1.28"
+#define VBOX_VERSION_STRING "5.1.28_Ubuntu"
+#define VBOX_API_VERSION_STRING "5_1"
+
+#define VBOX_PRIVATE_BUILD_DESC "Private build by buildd"
+
+#endif