VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR0/DBGFR0Bp.cpp@ 86763

Last change on this file since 86763 was 86704, checked in by vboxsync, 4 years ago

VMM/DBGF: Updates to the new breakpoint manager, L2 table management groundwork, bugref:9837

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.2 KB
Line 
1/* $Id: DBGFR0Bp.cpp 86704 2020-10-26 12:04:05Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, R0 breakpoint management part.
4 */
5
6/*
7 * Copyright (C) 2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DBGF
23#include "DBGFInternal.h"
24#include <VBox/vmm/gvm.h>
25#include <VBox/vmm/gvmm.h>
26#include <VBox/vmm/vmm.h>
27
28#include <VBox/log.h>
29#include <VBox/sup.h>
30#include <iprt/asm.h>
31#include <iprt/assert.h>
32#include <iprt/errcore.h>
33#include <iprt/ctype.h>
34#include <iprt/mem.h>
35#include <iprt/memobj.h>
36#include <iprt/process.h>
37#include <iprt/string.h>
38
39#include "dtrace/VBoxVMM.h"
40
41
42/*********************************************************************************************************************************
43* Internal Functions *
44*********************************************************************************************************************************/
45
46/**
47 * Used by DBGFR0InitPerVM() to initialize the breakpoint manager.
48 *
49 * @returns nothing.
50 * @param pGVM The global (ring-0) VM structure.
51 */
52DECLHIDDEN(void) dbgfR0BpInit(PGVM pGVM)
53{
54 for (uint32_t i = 0; i < RT_ELEMENTS(pGVM->dbgfr0.s.aBpChunks); i++)
55 {
56 PDBGFBPCHUNKR0 pBpChunk = &pGVM->dbgfr0.s.aBpChunks[i];
57
58 pBpChunk->hMemObj = NIL_RTR0MEMOBJ;
59 pBpChunk->hMapObj = NIL_RTR0MEMOBJ;
60 //pBpChunk->paBpBaseSharedR0 = NULL;
61 //pBpChunk->paBpBaseR0Only = NULL;
62 }
63
64 for (uint32_t i = 0; i < RT_ELEMENTS(pGVM->dbgfr0.s.aBpL2TblChunks); i++)
65 {
66 PDBGFBPL2TBLCHUNKR0 pL2Chunk = &pGVM->dbgfr0.s.aBpL2TblChunks[i];
67
68 pL2Chunk->hMemObj = NIL_RTR0MEMOBJ;
69 pL2Chunk->hMapObj = NIL_RTR0MEMOBJ;
70 //pL2Chunk->paBpL2TblBaseSharedR0 = NULL;
71 }
72
73 pGVM->dbgfr0.s.hMemObjBpLocL1 = NIL_RTR0MEMOBJ;
74 //pGVM->dbgfr0.s.paBpLocL1R0 = NULL;
75 //pGVM->dbgfr0.s.fInit = false;
76}
77
78
79/**
80 * Used by DBGFR0CleanupVM to destroy the breakpoint manager.
81 *
82 * This is done during VM cleanup so that we're sure there are no active threads
83 * using the breakpoint code.
84 *
85 * @param pGVM The global (ring-0) VM structure.
86 */
87DECLHIDDEN(void) dbgfR0BpDestroy(PGVM pGVM)
88{
89 if (pGVM->dbgfr0.s.fInit)
90 {
91 Assert(pGVM->dbgfr0.s.hMemObjBpLocL1 != NIL_RTR0MEMOBJ);
92 AssertPtr(pGVM->dbgfr0.s.paBpLocL1R0);
93
94 /*
95 * Free all allocated memory and ring-3 mapping objects.
96 */
97 RTR0MEMOBJ hMemObj = pGVM->dbgfr0.s.hMemObjBpLocL1;
98 pGVM->dbgfr0.s.hMemObjBpLocL1 = NIL_RTR0MEMOBJ;
99 pGVM->dbgfr0.s.paBpLocL1R0 = NULL;
100 RTR0MemObjFree(hMemObj, true);
101
102 for (uint32_t i = 0; i < RT_ELEMENTS(pGVM->dbgfr0.s.aBpChunks); i++)
103 {
104 PDBGFBPCHUNKR0 pBpChunk = &pGVM->dbgfr0.s.aBpChunks[i];
105
106 if (pBpChunk->hMemObj != NIL_RTR0MEMOBJ)
107 {
108 Assert(pBpChunk->hMapObj != NIL_RTR0MEMOBJ);
109
110 pBpChunk->paBpBaseSharedR0 = NULL;
111 pBpChunk->paBpBaseR0Only = NULL;
112
113 hMemObj = pBpChunk->hMapObj;
114 pBpChunk->hMapObj = NIL_RTR0MEMOBJ;
115 RTR0MemObjFree(hMemObj, true);
116
117 hMemObj = pBpChunk->hMemObj;
118 pBpChunk->hMemObj = NIL_RTR0MEMOBJ;
119 RTR0MemObjFree(hMemObj, true);
120 }
121 }
122
123 for (uint32_t i = 0; i < RT_ELEMENTS(pGVM->dbgfr0.s.aBpL2TblChunks); i++)
124 {
125 PDBGFBPL2TBLCHUNKR0 pL2Chunk = &pGVM->dbgfr0.s.aBpL2TblChunks[i];
126
127 if (pL2Chunk->hMemObj != NIL_RTR0MEMOBJ)
128 {
129 Assert(pL2Chunk->hMapObj != NIL_RTR0MEMOBJ);
130
131 pL2Chunk->paBpL2TblBaseSharedR0 = NULL;
132
133 hMemObj = pL2Chunk->hMapObj;
134 pL2Chunk->hMapObj = NIL_RTR0MEMOBJ;
135 RTR0MemObjFree(hMemObj, true);
136
137 hMemObj = pL2Chunk->hMemObj;
138 pL2Chunk->hMemObj = NIL_RTR0MEMOBJ;
139 RTR0MemObjFree(hMemObj, true);
140 }
141 }
142
143 pGVM->dbgfr0.s.fInit = false;
144 }
145#ifdef RT_STRICT
146 else
147 {
148 Assert(pGVM->dbgfr0.s.hMemObjBpLocL1 == NIL_RTR0MEMOBJ);
149 Assert(!pGVM->dbgfr0.s.paBpLocL1R0);
150
151 for (uint32_t i = 0; i < RT_ELEMENTS(pGVM->dbgfr0.s.aBpChunks); i++)
152 {
153 PDBGFBPCHUNKR0 pBpChunk = &pGVM->dbgfr0.s.aBpChunks[i];
154
155 Assert(pBpChunk->hMemObj == NIL_RTR0MEMOBJ);
156 Assert(pBpChunk->hMapObj == NIL_RTR0MEMOBJ);
157 Assert(!pBpChunk->paBpBaseSharedR0);
158 Assert(!pBpChunk->paBpBaseR0Only);
159 }
160
161 for (uint32_t i = 0; i < RT_ELEMENTS(pGVM->dbgfr0.s.aBpL2TblChunks); i++)
162 {
163 PDBGFBPL2TBLCHUNKR0 pL2Chunk = &pGVM->dbgfr0.s.aBpL2TblChunks[i];
164
165 Assert(pL2Chunk->hMemObj == NIL_RTR0MEMOBJ);
166 Assert(pL2Chunk->hMapObj == NIL_RTR0MEMOBJ);
167 Assert(!pL2Chunk->paBpL2TblBaseSharedR0);
168 }
169 }
170#endif
171}
172
173
174/**
175 * Worker for DBGFR0BpInitReqHandler() that does the actual initialization.
176 *
177 * @returns VBox status code.
178 * @param pGVM The global (ring-0) VM structure.
179 * @param ppaBpLocL1R3 Where to return the ring-3 L1 lookup table address on success.
180 * @thread EMT(0)
181 */
182static int dbgfR0BpInitWorker(PGVM pGVM, R3PTRTYPE(volatile uint32_t *) *ppaBpLocL1R3)
183{
184 /*
185 * Figure out how much memory we need for the L1 lookup table and allocate it.
186 */
187 uint32_t const cbL1Loc = RT_ALIGN_32(UINT16_MAX * sizeof(uint32_t), PAGE_SIZE);
188
189 RTR0MEMOBJ hMemObj;
190 int rc = RTR0MemObjAllocPage(&hMemObj, cbL1Loc, false /*fExecutable*/);
191 if (RT_FAILURE(rc))
192 return rc;
193 RT_BZERO(RTR0MemObjAddress(hMemObj), cbL1Loc);
194
195 /* Map it. */
196 RTR0MEMOBJ hMapObj;
197 rc = RTR0MemObjMapUserEx(&hMapObj, hMemObj, (RTR3PTR)-1, 0, RTMEM_PROT_READ | RTMEM_PROT_WRITE, RTR0ProcHandleSelf(),
198 0 /*offSub*/, cbL1Loc);
199 if (RT_SUCCESS(rc))
200 {
201 pGVM->dbgfr0.s.hMemObjBpLocL1 = hMemObj;
202 pGVM->dbgfr0.s.hMapObjBpLocL1 = hMapObj;
203 pGVM->dbgfr0.s.paBpLocL1R0 = (volatile uint32_t *)RTR0MemObjAddress(hMemObj);
204
205 /*
206 * We're done.
207 */
208 *ppaBpLocL1R3 = RTR0MemObjAddressR3(hMapObj);
209 pGVM->dbgfr0.s.fInit = true;
210 return rc;
211 }
212
213 RTR0MemObjFree(hMemObj, true);
214 return rc;
215}
216
217
218/**
219 * Worker for DBGFR0BpChunkAllocReqHandler() that does the actual chunk allocation.
220 *
221 * Allocates a memory object and divides it up as follows:
222 * @verbatim
223 --------------------------------------
224 ring-0 chunk data
225 --------------------------------------
226 page alignment padding
227 --------------------------------------
228 shared chunk data
229 --------------------------------------
230 @endverbatim
231 *
232 * @returns VBox status code.
233 * @param pGVM The global (ring-0) VM structure.
234 * @param idChunk The chunk ID to allocate.
235 * @param ppBpChunkBaseR3 Where to return the ring-3 chunk base address on success.
236 * @thread EMT(0)
237 */
238static int dbgfR0BpChunkAllocWorker(PGVM pGVM, uint32_t idChunk, R3PTRTYPE(void *) *ppBpChunkBaseR3)
239{
240 /*
241 * Figure out how much memory we need for the chunk and allocate it.
242 */
243 uint32_t const cbRing0 = RT_ALIGN_32(DBGF_BP_COUNT_PER_CHUNK * sizeof(DBGFBPINTR0), PAGE_SIZE);
244 uint32_t const cbShared = RT_ALIGN_32(DBGF_BP_COUNT_PER_CHUNK * sizeof(DBGFBPINT), PAGE_SIZE);
245 uint32_t const cbTotal = cbRing0 + cbShared;
246
247 RTR0MEMOBJ hMemObj;
248 int rc = RTR0MemObjAllocPage(&hMemObj, cbTotal, false /*fExecutable*/);
249 if (RT_FAILURE(rc))
250 return rc;
251 RT_BZERO(RTR0MemObjAddress(hMemObj), cbTotal);
252
253 /* Map it. */
254 RTR0MEMOBJ hMapObj;
255 rc = RTR0MemObjMapUserEx(&hMapObj, hMemObj, (RTR3PTR)-1, 0, RTMEM_PROT_READ | RTMEM_PROT_WRITE, RTR0ProcHandleSelf(),
256 cbRing0 /*offSub*/, cbTotal - cbRing0);
257 if (RT_SUCCESS(rc))
258 {
259 PDBGFBPCHUNKR0 pBpChunkR0 = &pGVM->dbgfr0.s.aBpChunks[idChunk];
260
261 pBpChunkR0->hMemObj = hMemObj;
262 pBpChunkR0->hMapObj = hMapObj;
263 pBpChunkR0->paBpBaseR0Only = (PDBGFBPINTR0)RTR0MemObjAddress(hMemObj);
264 pBpChunkR0->paBpBaseSharedR0 = (PDBGFBPINT)&pBpChunkR0->paBpBaseR0Only[DBGF_BP_COUNT_PER_CHUNK];
265
266 /*
267 * We're done.
268 */
269 *ppBpChunkBaseR3 = RTR0MemObjAddressR3(hMapObj);
270 return rc;
271 }
272
273 RTR0MemObjFree(hMemObj, true);
274 return rc;
275}
276
277
278/**
279 * Worker for DBGFR0BpL2TblChunkAllocReqHandler() that does the actual chunk allocation.
280 *
281 * @returns VBox status code.
282 * @param pGVM The global (ring-0) VM structure.
283 * @param idChunk The chunk ID to allocate.
284 * @param ppL2ChunkBaseR3 Where to return the ring-3 chunk base address on success.
285 * @thread EMT(0)
286 */
287static int dbgfR0BpL2TblChunkAllocWorker(PGVM pGVM, uint32_t idChunk, R3PTRTYPE(void *) *ppL2ChunkBaseR3)
288{
289 /*
290 * Figure out how much memory we need for the chunk and allocate it.
291 */
292 uint32_t const cbTotal = RT_ALIGN_32(DBGF_BP_L2_TBL_ENTRIES_PER_CHUNK * sizeof(DBGFBPL2ENTRY), PAGE_SIZE);
293
294 RTR0MEMOBJ hMemObj;
295 int rc = RTR0MemObjAllocPage(&hMemObj, cbTotal, false /*fExecutable*/);
296 if (RT_FAILURE(rc))
297 return rc;
298 RT_BZERO(RTR0MemObjAddress(hMemObj), cbTotal);
299
300 /* Map it. */
301 RTR0MEMOBJ hMapObj;
302 rc = RTR0MemObjMapUserEx(&hMapObj, hMemObj, (RTR3PTR)-1, 0, RTMEM_PROT_READ | RTMEM_PROT_WRITE, RTR0ProcHandleSelf(),
303 0 /*offSub*/, cbTotal);
304 if (RT_SUCCESS(rc))
305 {
306 PDBGFBPL2TBLCHUNKR0 pL2ChunkR0 = &pGVM->dbgfr0.s.aBpL2TblChunks[idChunk];
307
308 pL2ChunkR0->hMemObj = hMemObj;
309 pL2ChunkR0->hMapObj = hMapObj;
310 pL2ChunkR0->paBpL2TblBaseSharedR0 = (PDBGFBPL2ENTRY)RTR0MemObjAddress(hMemObj);
311
312 /*
313 * We're done.
314 */
315 *ppL2ChunkBaseR3 = RTR0MemObjAddressR3(hMapObj);
316 return rc;
317 }
318
319 RTR0MemObjFree(hMemObj, true);
320 return rc;
321}
322
323
324/**
325 * Used by ring-3 DBGF to fully initialize the breakpoint manager for operation.
326 *
327 * @returns VBox status code.
328 * @param pGVM The global (ring-0) VM structure.
329 * @param pReq Pointer to the request buffer.
330 * @thread EMT(0)
331 */
332VMMR0_INT_DECL(int) DBGFR0BpInitReqHandler(PGVM pGVM, PDBGFBPINITREQ pReq)
333{
334 LogFlow(("DBGFR0BpInitReqHandler:\n"));
335
336 /*
337 * Validate the request.
338 */
339 AssertReturn(pReq->Hdr.cbReq == sizeof(*pReq), VERR_INVALID_PARAMETER);
340
341 int rc = GVMMR0ValidateGVMandEMT(pGVM, 0);
342 AssertRCReturn(rc, rc);
343
344 AssertReturn(!pGVM->dbgfr0.s.fInit, VERR_WRONG_ORDER);
345
346 return dbgfR0BpInitWorker(pGVM, &pReq->paBpLocL1R3);
347}
348
349
350/**
351 * Used by ring-3 DBGF to allocate a given chunk in the global breakpoint table.
352 *
353 * @returns VBox status code.
354 * @param pGVM The global (ring-0) VM structure.
355 * @param pReq Pointer to the request buffer.
356 * @thread EMT(0)
357 */
358VMMR0_INT_DECL(int) DBGFR0BpChunkAllocReqHandler(PGVM pGVM, PDBGFBPCHUNKALLOCREQ pReq)
359{
360 LogFlow(("DBGFR0BpChunkAllocReqHandler:\n"));
361
362 /*
363 * Validate the request.
364 */
365 AssertReturn(pReq->Hdr.cbReq == sizeof(*pReq), VERR_INVALID_PARAMETER);
366
367 uint32_t const idChunk = pReq->idChunk;
368 AssertReturn(idChunk < DBGF_BP_CHUNK_COUNT, VERR_INVALID_PARAMETER);
369
370 int rc = GVMMR0ValidateGVMandEMT(pGVM, 0);
371 AssertRCReturn(rc, rc);
372
373 AssertReturn(pGVM->dbgfr0.s.fInit, VERR_WRONG_ORDER);
374 AssertReturn(pGVM->dbgfr0.s.aBpChunks[idChunk].hMemObj == NIL_RTR0MEMOBJ, VERR_INVALID_PARAMETER);
375
376 return dbgfR0BpChunkAllocWorker(pGVM, idChunk, &pReq->pChunkBaseR3);
377}
378
379
380/**
381 * Used by ring-3 DBGF to allocate a given chunk in the global L2 lookup table.
382 *
383 * @returns VBox status code.
384 * @param pGVM The global (ring-0) VM structure.
385 * @param pReq Pointer to the request buffer.
386 * @thread EMT(0)
387 */
388VMMR0_INT_DECL(int) DBGFR0BpL2TblChunkAllocReqHandler(PGVM pGVM, PDBGFBPL2TBLCHUNKALLOCREQ pReq)
389{
390 LogFlow(("DBGFR0BpL2TblChunkAllocReqHandler:\n"));
391
392 /*
393 * Validate the request.
394 */
395 AssertReturn(pReq->Hdr.cbReq == sizeof(*pReq), VERR_INVALID_PARAMETER);
396
397 uint32_t const idChunk = pReq->idChunk;
398 AssertReturn(idChunk < DBGF_BP_L2_TBL_CHUNK_COUNT, VERR_INVALID_PARAMETER);
399
400 int rc = GVMMR0ValidateGVMandEMT(pGVM, 0);
401 AssertRCReturn(rc, rc);
402
403 AssertReturn(pGVM->dbgfr0.s.fInit, VERR_WRONG_ORDER);
404 AssertReturn(pGVM->dbgfr0.s.aBpL2TblChunks[idChunk].hMemObj == NIL_RTR0MEMOBJ, VERR_INVALID_PARAMETER);
405
406 return dbgfR0BpL2TblChunkAllocWorker(pGVM, idChunk, &pReq->pChunkBaseR3);
407}
408
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette