diff options
Diffstat (limited to 'src/VBox/Devices/Misc')
-rw-r--r-- | src/VBox/Devices/Misc/DevVirtualKD.cpp | 303 | ||||
-rw-r--r-- | src/VBox/Devices/Misc/Makefile.kup | 0 |
2 files changed, 303 insertions, 0 deletions
diff --git a/src/VBox/Devices/Misc/DevVirtualKD.cpp b/src/VBox/Devices/Misc/DevVirtualKD.cpp new file mode 100644 index 00000000..acfc7311 --- /dev/null +++ b/src/VBox/Devices/Misc/DevVirtualKD.cpp @@ -0,0 +1,303 @@ +/* $Id: DevVirtualKD.cpp $ */ +/** @file + * VirtualKD - Device stub/loader for fast Windows kernel-mode debugging. + * + * Contributed by: Ivan Shcherbakov + * Heavily modified after the contribution. + */ + +/* + * Copyright (C) 2010-2020 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#define LOG_GROUP LOG_GROUP_DEV // LOG_GROUP_DEV_VIRTUALKD +#include <VBox/vmm/pdmdev.h> +#include <VBox/log.h> +#include <iprt/assert.h> +#include <iprt/path.h> + +#include "VBoxDD.h" + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +#define IKDClient_InterfaceVersion 3 + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +typedef struct VKDREQUESTHDR +{ + unsigned cbData; + unsigned cbReplyMax; +} VKDREQUESTHDR; + +#pragma pack(1) +typedef struct VKDREPLYHDR +{ + unsigned cbData; + char chOne; + char chSpace; +} VKDREPLYHDR; +#pragma pack() +AssertCompileSize(VKDREPLYHDR, 6); + +class IKDClient +{ +public: + virtual unsigned OnRequest(const char *pRequestIncludingRpcHeader, unsigned RequestSizeWithRpcHeader, char **ppReply)=0; + virtual ~IKDClient() {} +}; + +typedef IKDClient *(*PFNCreateVBoxKDClientEx)(unsigned version); + +typedef struct VIRTUALKD +{ + bool fOpenChannelDetected; + bool fChannelDetectSuccessful; + RTLDRMOD hLib; + IKDClient *pKDClient; + char abCmdBody[_256K]; +} VIRTUALKD; + + + + +static DECLCALLBACK(VBOXSTRICTRC) vkdPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb) +{ + RT_NOREF(pvUser, offPort, cb); + VIRTUALKD *pThis = PDMDEVINS_2_DATA(pDevIns, VIRTUALKD *); + + if (pThis->fOpenChannelDetected) + { + *pu32 = RT_MAKE_U32_FROM_U8('V', 'B', 'O', 'X'); /* 'XOBV', checked in VMWRPC.H */ + pThis->fOpenChannelDetected = false; + pThis->fChannelDetectSuccessful = true; + } + else + *pu32 = UINT32_MAX; + + return VINF_SUCCESS; +} + +static DECLCALLBACK(VBOXSTRICTRC) vkdPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb) +{ + RT_NOREF(pvUser, cb); + VIRTUALKD *pThis = PDMDEVINS_2_DATA(pDevIns, VIRTUALKD *); + + if (offPort == 1) + { + RTGCPHYS GCPhys = u32; + VKDREQUESTHDR RequestHeader = {0, }; + int rc = PDMDevHlpPhysRead(pDevIns, GCPhys, &RequestHeader, sizeof(RequestHeader)); + if ( !RT_SUCCESS(rc) + || !RequestHeader.cbData) + return VINF_SUCCESS; + + unsigned cbData = RT_MIN(RequestHeader.cbData, sizeof(pThis->abCmdBody)); + rc = PDMDevHlpPhysRead(pDevIns, GCPhys + sizeof(RequestHeader), pThis->abCmdBody, cbData); + if (!RT_SUCCESS(rc)) + return VINF_SUCCESS; + + char *pReply = NULL; + unsigned cbReply = pThis->pKDClient->OnRequest(pThis->abCmdBody, cbData, &pReply); + + if (!pReply) + cbReply = 0; + + /** @todo r=bird: RequestHeader.cbReplyMax is not taking into account here. */ + VKDREPLYHDR ReplyHeader; + ReplyHeader.cbData = cbReply + 2; + ReplyHeader.chOne = '1'; + ReplyHeader.chSpace = ' '; + rc = PDMDevHlpPhysWrite(pDevIns, GCPhys, &ReplyHeader, sizeof(ReplyHeader)); + if (!RT_SUCCESS(rc)) + return VINF_SUCCESS; + if (cbReply) + { + rc = PDMDevHlpPhysWrite(pDevIns, GCPhys + sizeof(ReplyHeader), pReply, cbReply); + if (!RT_SUCCESS(rc)) + return VINF_SUCCESS; + } + } + else + { + Assert(offPort == 0); + if (u32 == 0x564D5868) + pThis->fOpenChannelDetected = true; + else + pThis->fOpenChannelDetected = false; + } + + return VINF_SUCCESS; +} + + +/** + * @interface_method_impl{PDMDEVREG,pfnDestruct} + */ +static DECLCALLBACK(int) vkdDestruct(PPDMDEVINS pDevIns) +{ + PDMDEV_CHECK_VERSIONS_RETURN(pDevIns); + VIRTUALKD *pThis = PDMDEVINS_2_DATA(pDevIns, VIRTUALKD *); + + if (pThis->pKDClient) + { + delete pThis->pKDClient; + pThis->pKDClient = NULL; + } + + if (pThis->hLib != NIL_RTLDRMOD) + { + RTLdrClose(pThis->hLib); + pThis->hLib = NIL_RTLDRMOD; + } + + return VINF_SUCCESS; +} + + +/** + * @interface_method_impl{PDMDEVREG,pfnConstruct} + */ +static DECLCALLBACK(int) vkdConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg) +{ + PDMDEV_CHECK_VERSIONS_RETURN(pDevIns); + VIRTUALKD *pThis = PDMDEVINS_2_DATA(pDevIns, VIRTUALKD *); + RT_NOREF(iInstance); + + pThis->fOpenChannelDetected = false; + pThis->fChannelDetectSuccessful = false; + pThis->hLib = NIL_RTLDRMOD; + pThis->pKDClient = NULL; + + + PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "Path", ""); + + /* This device is a bit unusual, after this point it will not fail to be + * constructed, but there will be a warning and it will not work. */ + + char szPath[RTPATH_MAX]; + int rc = CFGMR3QueryStringDef(pCfg, "Path", szPath, sizeof(szPath) - sizeof("kdclient64.dll"), ""); + if (RT_FAILURE(rc)) + return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"Path\" value")); + + rc = RTPathAppend(szPath, sizeof(szPath), HC_ARCH_BITS == 64 ? "kdclient64.dll" : "kdclient.dll"); + AssertRCReturn(rc, rc); + rc = RTLdrLoad(szPath, &pThis->hLib); + if (RT_SUCCESS(rc)) + { + PFNCreateVBoxKDClientEx pfnInit; + rc = RTLdrGetSymbol(pThis->hLib, "CreateVBoxKDClientEx", (void **)&pfnInit); + if (RT_SUCCESS(rc)) + { + pThis->pKDClient = pfnInit(IKDClient_InterfaceVersion); + if (pThis->pKDClient) + { + IOMIOPORTHANDLE hIoPorts; + rc = PDMDevHlpIoPortCreateAndMap(pDevIns, 0x5658 /*uPort*/, 2 /*cPorts*/, vkdPortWrite, vkdPortRead, + "VirtualKD", NULL /*paExtDescs*/, &hIoPorts); + AssertRCReturn(rc, rc); + } + else + PDMDevHlpVMSetRuntimeError(pDevIns, 0 /* fFlags */, "VirtualKD_INIT", + N_("Failed to initialize VirtualKD library '%s'. Fast kernel-mode debugging will not work"), szPath); + } + else + PDMDevHlpVMSetRuntimeError(pDevIns, 0 /* fFlags */, "VirtualKD_SYMBOL", + N_("Failed to find entry point for VirtualKD library '%s'. Fast kernel-mode debugging will not work"), szPath); + } + else + PDMDevHlpVMSetRuntimeError(pDevIns, 0 /* fFlags */, "VirtualKD_LOAD", + N_("Failed to load VirtualKD library '%s'. Fast kernel-mode debugging will not work"), szPath); + return VINF_SUCCESS; +} + + +/** + * The device registration structure. + */ +const PDMDEVREG g_DeviceVirtualKD = +{ + /* .u32Version = */ PDM_DEVREG_VERSION, + /* .uReserved0 = */ 0, + /* .szName = */ "VirtualKD", + /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_NEW_STYLE, + /* .fClass = */ PDM_DEVREG_CLASS_MISC, + /* .cMaxInstances = */ 1, + /* .uSharedVersion = */ 42, + /* .cbInstanceShared = */ sizeof(VIRTUALKD), + /* .cbInstanceCC = */ 0, + /* .cbInstanceRC = */ 0, + /* .cMaxPciDevices = */ 0, + /* .cMaxMsixVectors = */ 0, + /* .pszDescription = */ "Provides fast debugging interface when debugging Windows kernel", +#if defined(IN_RING3) + /* .pszRCMod = */ "", + /* .pszR0Mod = */ "", + /* .pfnConstruct = */ vkdConstruct, + /* .pfnDestruct = */ vkdDestruct, + /* .pfnRelocate = */ NULL, + /* pfnIOCtl */ NULL, + /* .pfnPowerOn = */ NULL, + /* .pfnReset = */ NULL, + /* .pfnSuspend = */ NULL, + /* .pfnResume = */ NULL, + /* .pfnAttach = */ NULL, + /* .pfnDetach = */ NULL, + /* .pfnQueryInterface = */ NULL, + /* .pfnInitComplete = */ NULL, + /* .pfnPowerOff = */ NULL, + /* .pfnSoftReset = */ NULL, + /* .pfnReserved0 = */ NULL, + /* .pfnReserved1 = */ NULL, + /* .pfnReserved2 = */ NULL, + /* .pfnReserved3 = */ NULL, + /* .pfnReserved4 = */ NULL, + /* .pfnReserved5 = */ NULL, + /* .pfnReserved6 = */ NULL, + /* .pfnReserved7 = */ NULL, +#elif defined(IN_RING0) + /* .pfnEarlyConstruct = */ NULL, + /* .pfnConstruct = */ NULL, + /* .pfnDestruct = */ NULL, + /* .pfnFinalDestruct = */ NULL, + /* .pfnRequest = */ NULL, + /* .pfnReserved0 = */ NULL, + /* .pfnReserved1 = */ NULL, + /* .pfnReserved2 = */ NULL, + /* .pfnReserved3 = */ NULL, + /* .pfnReserved4 = */ NULL, + /* .pfnReserved5 = */ NULL, + /* .pfnReserved6 = */ NULL, + /* .pfnReserved7 = */ NULL, +#elif defined(IN_RC) + /* .pfnConstruct = */ NULL, + /* .pfnReserved0 = */ NULL, + /* .pfnReserved1 = */ NULL, + /* .pfnReserved2 = */ NULL, + /* .pfnReserved3 = */ NULL, + /* .pfnReserved4 = */ NULL, + /* .pfnReserved5 = */ NULL, + /* .pfnReserved6 = */ NULL, + /* .pfnReserved7 = */ NULL, +#else +# error "Not in IN_RING3, IN_RING0 or IN_RC!" +#endif + /* .u32VersionEnd = */ PDM_DEVREG_VERSION +}; + diff --git a/src/VBox/Devices/Misc/Makefile.kup b/src/VBox/Devices/Misc/Makefile.kup new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/VBox/Devices/Misc/Makefile.kup |