VirtualBox

source: vbox/trunk/src/VBox/Devices/Misc/DevVirtualKD.cpp@ 82781

Last change on this file since 82781 was 82149, checked in by vboxsync, 5 years ago

VirtualKD -> DevVirtualKD

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.6 KB
Line 
1/* $Id: DevVirtualKD.cpp 82149 2019-11-24 16:25:49Z vboxsync $ */
2/** @file
3 * VirtualKD - Device stub/loader for fast Windows kernel-mode debugging.
4 *
5 * Contributed by: Ivan Shcherbakov
6 * Heavily modified after the contribution.
7 */
8
9/*
10 * Copyright (C) 2010-2019 Oracle Corporation
11 *
12 * This file is part of VirtualBox Open Source Edition (OSE), as
13 * available from http://www.virtualbox.org. This file is free software;
14 * you can redistribute it and/or modify it under the terms of the GNU
15 * General Public License (GPL) as published by the Free Software
16 * Foundation, in version 2 as it comes in the "COPYING" file of the
17 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19 */
20
21
22/*********************************************************************************************************************************
23* Header Files *
24*********************************************************************************************************************************/
25#define LOG_GROUP LOG_GROUP_DEV // LOG_GROUP_DEV_VIRTUALKD
26#include <VBox/vmm/pdmdev.h>
27#include <VBox/log.h>
28#include <iprt/assert.h>
29#include <iprt/path.h>
30
31#include "VBoxDD.h"
32
33
34/*********************************************************************************************************************************
35* Defined Constants And Macros *
36*********************************************************************************************************************************/
37#define IKDClient_InterfaceVersion 3
38
39
40/*********************************************************************************************************************************
41* Structures and Typedefs *
42*********************************************************************************************************************************/
43typedef struct VKDREQUESTHDR
44{
45 unsigned cbData;
46 unsigned cbReplyMax;
47} VKDREQUESTHDR;
48
49#pragma pack(1)
50typedef struct VKDREPLYHDR
51{
52 unsigned cbData;
53 char chOne;
54 char chSpace;
55} VKDREPLYHDR;
56#pragma pack()
57AssertCompileSize(VKDREPLYHDR, 6);
58
59class IKDClient
60{
61public:
62 virtual unsigned OnRequest(const char *pRequestIncludingRpcHeader, unsigned RequestSizeWithRpcHeader, char **ppReply)=0;
63 virtual ~IKDClient() {}
64};
65
66typedef IKDClient *(*PFNCreateVBoxKDClientEx)(unsigned version);
67
68typedef struct VIRTUALKD
69{
70 bool fOpenChannelDetected;
71 bool fChannelDetectSuccessful;
72 RTLDRMOD hLib;
73 IKDClient *pKDClient;
74 char abCmdBody[_256K];
75} VIRTUALKD;
76
77
78
79
80static DECLCALLBACK(VBOXSTRICTRC) vkdPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
81{
82 RT_NOREF(pvUser, offPort, cb);
83 VIRTUALKD *pThis = PDMDEVINS_2_DATA(pDevIns, VIRTUALKD *);
84
85 if (pThis->fOpenChannelDetected)
86 {
87 *pu32 = RT_MAKE_U32_FROM_U8('V', 'B', 'O', 'X'); /* 'XOBV', checked in VMWRPC.H */
88 pThis->fOpenChannelDetected = false;
89 pThis->fChannelDetectSuccessful = true;
90 }
91 else
92 *pu32 = UINT32_MAX;
93
94 return VINF_SUCCESS;
95}
96
97static DECLCALLBACK(VBOXSTRICTRC) vkdPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
98{
99 RT_NOREF(pvUser, cb);
100 VIRTUALKD *pThis = PDMDEVINS_2_DATA(pDevIns, VIRTUALKD *);
101
102 if (offPort == 1)
103 {
104 RTGCPHYS GCPhys = u32;
105 VKDREQUESTHDR RequestHeader = {0, };
106 int rc = PDMDevHlpPhysRead(pDevIns, GCPhys, &RequestHeader, sizeof(RequestHeader));
107 if ( !RT_SUCCESS(rc)
108 || !RequestHeader.cbData)
109 return VINF_SUCCESS;
110
111 unsigned cbData = RT_MIN(RequestHeader.cbData, sizeof(pThis->abCmdBody));
112 rc = PDMDevHlpPhysRead(pDevIns, GCPhys + sizeof(RequestHeader), pThis->abCmdBody, cbData);
113 if (!RT_SUCCESS(rc))
114 return VINF_SUCCESS;
115
116 char *pReply = NULL;
117 unsigned cbReply = pThis->pKDClient->OnRequest(pThis->abCmdBody, cbData, &pReply);
118
119 if (!pReply)
120 cbReply = 0;
121
122 /** @todo r=bird: RequestHeader.cbReplyMax is not taking into account here. */
123 VKDREPLYHDR ReplyHeader;
124 ReplyHeader.cbData = cbReply + 2;
125 ReplyHeader.chOne = '1';
126 ReplyHeader.chSpace = ' ';
127 rc = PDMDevHlpPhysWrite(pDevIns, GCPhys, &ReplyHeader, sizeof(ReplyHeader));
128 if (!RT_SUCCESS(rc))
129 return VINF_SUCCESS;
130 if (cbReply)
131 {
132 rc = PDMDevHlpPhysWrite(pDevIns, GCPhys + sizeof(ReplyHeader), pReply, cbReply);
133 if (!RT_SUCCESS(rc))
134 return VINF_SUCCESS;
135 }
136 }
137 else
138 {
139 Assert(offPort == 0);
140 if (u32 == 0x564D5868)
141 pThis->fOpenChannelDetected = true;
142 else
143 pThis->fOpenChannelDetected = false;
144 }
145
146 return VINF_SUCCESS;
147}
148
149
150/**
151 * @interface_method_impl{PDMDEVREG,pfnDestruct}
152 */
153static DECLCALLBACK(int) vkdDestruct(PPDMDEVINS pDevIns)
154{
155 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
156 VIRTUALKD *pThis = PDMDEVINS_2_DATA(pDevIns, VIRTUALKD *);
157
158 if (pThis->pKDClient)
159 {
160 delete pThis->pKDClient;
161 pThis->pKDClient = NULL;
162 }
163
164 if (pThis->hLib != NIL_RTLDRMOD)
165 {
166 RTLdrClose(pThis->hLib);
167 pThis->hLib = NIL_RTLDRMOD;
168 }
169
170 return VINF_SUCCESS;
171}
172
173
174/**
175 * @interface_method_impl{PDMDEVREG,pfnConstruct}
176 */
177static DECLCALLBACK(int) vkdConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
178{
179 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
180 VIRTUALKD *pThis = PDMDEVINS_2_DATA(pDevIns, VIRTUALKD *);
181 RT_NOREF(iInstance);
182
183 pThis->fOpenChannelDetected = false;
184 pThis->fChannelDetectSuccessful = false;
185 pThis->hLib = NIL_RTLDRMOD;
186 pThis->pKDClient = NULL;
187
188
189 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "Path", "");
190
191 /* This device is a bit unusual, after this point it will not fail to be
192 * constructed, but there will be a warning and it will not work. */
193
194 char szPath[RTPATH_MAX];
195 int rc = CFGMR3QueryStringDef(pCfg, "Path", szPath, sizeof(szPath) - sizeof("kdclient64.dll"), "");
196 if (RT_FAILURE(rc))
197 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"Path\" value"));
198
199 rc = RTPathAppend(szPath, sizeof(szPath), HC_ARCH_BITS == 64 ? "kdclient64.dll" : "kdclient.dll");
200 AssertRCReturn(rc, rc);
201 rc = RTLdrLoad(szPath, &pThis->hLib);
202 if (RT_SUCCESS(rc))
203 {
204 PFNCreateVBoxKDClientEx pfnInit;
205 rc = RTLdrGetSymbol(pThis->hLib, "CreateVBoxKDClientEx", (void **)&pfnInit);
206 if (RT_SUCCESS(rc))
207 {
208 pThis->pKDClient = pfnInit(IKDClient_InterfaceVersion);
209 if (pThis->pKDClient)
210 {
211 IOMIOPORTHANDLE hIoPorts;
212 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, 0x5658 /*uPort*/, 2 /*cPorts*/, vkdPortWrite, vkdPortRead,
213 "VirtualKD", NULL /*paExtDescs*/, &hIoPorts);
214 AssertRCReturn(rc, rc);
215 }
216 else
217 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /* fFlags */, "VirtualKD_INIT",
218 N_("Failed to initialize VirtualKD library '%s'. Fast kernel-mode debugging will not work"), szPath);
219 }
220 else
221 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /* fFlags */, "VirtualKD_SYMBOL",
222 N_("Failed to find entry point for VirtualKD library '%s'. Fast kernel-mode debugging will not work"), szPath);
223 }
224 else
225 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /* fFlags */, "VirtualKD_LOAD",
226 N_("Failed to load VirtualKD library '%s'. Fast kernel-mode debugging will not work"), szPath);
227 return VINF_SUCCESS;
228}
229
230
231/**
232 * The device registration structure.
233 */
234const PDMDEVREG g_DeviceVirtualKD =
235{
236 /* .u32Version = */ PDM_DEVREG_VERSION,
237 /* .uReserved0 = */ 0,
238 /* .szName = */ "VirtualKD",
239 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_NEW_STYLE,
240 /* .fClass = */ PDM_DEVREG_CLASS_MISC,
241 /* .cMaxInstances = */ 1,
242 /* .uSharedVersion = */ 42,
243 /* .cbInstanceShared = */ sizeof(VIRTUALKD),
244 /* .cbInstanceCC = */ 0,
245 /* .cbInstanceRC = */ 0,
246 /* .cMaxPciDevices = */ 0,
247 /* .cMaxMsixVectors = */ 0,
248 /* .pszDescription = */ "Provides fast debugging interface when debugging Windows kernel",
249#if defined(IN_RING3)
250 /* .pszRCMod = */ "",
251 /* .pszR0Mod = */ "",
252 /* .pfnConstruct = */ vkdConstruct,
253 /* .pfnDestruct = */ vkdDestruct,
254 /* .pfnRelocate = */ NULL,
255 /* pfnIOCtl */ NULL,
256 /* .pfnPowerOn = */ NULL,
257 /* .pfnReset = */ NULL,
258 /* .pfnSuspend = */ NULL,
259 /* .pfnResume = */ NULL,
260 /* .pfnAttach = */ NULL,
261 /* .pfnDetach = */ NULL,
262 /* .pfnQueryInterface = */ NULL,
263 /* .pfnInitComplete = */ NULL,
264 /* .pfnPowerOff = */ NULL,
265 /* .pfnSoftReset = */ NULL,
266 /* .pfnReserved0 = */ NULL,
267 /* .pfnReserved1 = */ NULL,
268 /* .pfnReserved2 = */ NULL,
269 /* .pfnReserved3 = */ NULL,
270 /* .pfnReserved4 = */ NULL,
271 /* .pfnReserved5 = */ NULL,
272 /* .pfnReserved6 = */ NULL,
273 /* .pfnReserved7 = */ NULL,
274#elif defined(IN_RING0)
275 /* .pfnEarlyConstruct = */ NULL,
276 /* .pfnConstruct = */ NULL,
277 /* .pfnDestruct = */ NULL,
278 /* .pfnFinalDestruct = */ NULL,
279 /* .pfnRequest = */ NULL,
280 /* .pfnReserved0 = */ NULL,
281 /* .pfnReserved1 = */ NULL,
282 /* .pfnReserved2 = */ NULL,
283 /* .pfnReserved3 = */ NULL,
284 /* .pfnReserved4 = */ NULL,
285 /* .pfnReserved5 = */ NULL,
286 /* .pfnReserved6 = */ NULL,
287 /* .pfnReserved7 = */ NULL,
288#elif defined(IN_RC)
289 /* .pfnConstruct = */ NULL,
290 /* .pfnReserved0 = */ NULL,
291 /* .pfnReserved1 = */ NULL,
292 /* .pfnReserved2 = */ NULL,
293 /* .pfnReserved3 = */ NULL,
294 /* .pfnReserved4 = */ NULL,
295 /* .pfnReserved5 = */ NULL,
296 /* .pfnReserved6 = */ NULL,
297 /* .pfnReserved7 = */ NULL,
298#else
299# error "Not in IN_RING3, IN_RING0 or IN_RC!"
300#endif
301 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
302};
303
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use