VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/DBGFAddr.cpp

Last change on this file was 103359, checked in by vboxsync, 3 months ago

VMM/DBGF,PDMLdr,PGM: Addressed parfait's complaints about uninitialized variables. bugref:3409

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 15.5 KB
Line 
1/* $Id: DBGFAddr.cpp 103359 2024-02-14 14:39:26Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, Mixed Address Methods.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_DBGF
33#include <VBox/vmm/dbgf.h>
34#include <VBox/vmm/pgm.h>
35#include <VBox/vmm/selm.h>
36#include <VBox/vmm/mm.h>
37#include <VBox/vmm/hm.h>
38#include "DBGFInternal.h"
39#include <VBox/vmm/vm.h>
40#include <VBox/vmm/uvm.h>
41
42#include <VBox/param.h>
43#include <VBox/err.h>
44#include <VBox/log.h>
45
46
47
48/**
49 * Common worker for DBGFR3AddrFromSelOff and DBGFR3AddrFromSelInfoOff.
50 */
51static int dbgfR3AddrFromSelInfoOffWorker(PDBGFADDRESS pAddress, PCDBGFSELINFO pSelInfo, RTUINTPTR off)
52{
53 if (pSelInfo->fFlags & (DBGFSELINFO_FLAGS_INVALID | DBGFSELINFO_FLAGS_NOT_PRESENT))
54 return pSelInfo->fFlags & DBGFSELINFO_FLAGS_NOT_PRESENT
55 ? VERR_SELECTOR_NOT_PRESENT
56 : VERR_INVALID_SELECTOR;
57
58 /** @todo This all goes voodoo in long mode. */
59 /* check limit. */
60 if (DBGFSelInfoIsExpandDown(pSelInfo))
61 {
62 if ( !pSelInfo->u.Raw.Gen.u1Granularity
63 && off > UINT32_C(0xffff))
64 return VERR_OUT_OF_SELECTOR_BOUNDS;
65 if (off <= pSelInfo->cbLimit)
66 return VERR_OUT_OF_SELECTOR_BOUNDS;
67 }
68 else if (off > pSelInfo->cbLimit)
69 return VERR_OUT_OF_SELECTOR_BOUNDS;
70
71 pAddress->FlatPtr = pSelInfo->GCPtrBase + off;
72
73 /** @todo fix all these selector tests! */
74 if ( !pSelInfo->GCPtrBase
75 && pSelInfo->u.Raw.Gen.u1Granularity
76 && pSelInfo->u.Raw.Gen.u1DefBig)
77 pAddress->fFlags = DBGFADDRESS_FLAGS_FLAT;
78 else if (pSelInfo->cbLimit <= UINT32_C(0xffff))
79 pAddress->fFlags = DBGFADDRESS_FLAGS_FAR16;
80 else if (pSelInfo->cbLimit <= UINT32_C(0xffffffff))
81 pAddress->fFlags = DBGFADDRESS_FLAGS_FAR32;
82 else
83 pAddress->fFlags = DBGFADDRESS_FLAGS_FAR64;
84
85 return VINF_SUCCESS;
86}
87
88
89/**
90 * Creates a mixed address from a Sel:off pair.
91 *
92 * @returns VBox status code.
93 * @param pUVM The user mode VM handle.
94 * @param idCpu The CPU ID.
95 * @param pAddress Where to store the mixed address.
96 * @param Sel The selector part.
97 * @param off The offset part.
98 */
99VMMR3DECL(int) DBGFR3AddrFromSelOff(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddress, RTSEL Sel, RTUINTPTR off)
100{
101 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
102 VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, VERR_INVALID_VM_HANDLE);
103 AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_PARAMETER);
104
105 pAddress->Sel = Sel;
106 pAddress->off = off;
107 if (Sel != DBGF_SEL_FLAT)
108 {
109 DBGFSELINFO SelInfo;
110 int rc = DBGFR3SelQueryInfo(pUVM, idCpu, Sel, DBGFSELQI_FLAGS_DT_GUEST | DBGFSELQI_FLAGS_DT_ADJ_64BIT_MODE, &SelInfo);
111 if (RT_FAILURE(rc))
112 return rc;
113 rc = dbgfR3AddrFromSelInfoOffWorker(pAddress, &SelInfo, off);
114 if (RT_FAILURE(rc))
115 return rc;
116 }
117 else
118 {
119 pAddress->FlatPtr = off;
120 pAddress->fFlags = DBGFADDRESS_FLAGS_FLAT;
121 }
122 pAddress->fFlags |= DBGFADDRESS_FLAGS_VALID;
123
124 return VINF_SUCCESS;
125}
126
127
128/**
129 * Creates a mixed address from selector info and an offset into the segment
130 * described by it.
131 *
132 * @returns VBox status code.
133 * @param pUVM The user mode VM handle.
134 * @param pAddress Where to store the mixed address.
135 * @param pSelInfo The selector info.
136 * @param off The offset part.
137 */
138VMMR3DECL(int) DBGFR3AddrFromSelInfoOff(PUVM pUVM, PDBGFADDRESS pAddress, PCDBGFSELINFO pSelInfo, RTUINTPTR off)
139{
140 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
141 VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, VERR_INVALID_VM_HANDLE);
142
143 pAddress->Sel = pSelInfo->Sel;
144 pAddress->off = off;
145 int rc = dbgfR3AddrFromSelInfoOffWorker(pAddress, pSelInfo, off);
146 if (RT_FAILURE(rc))
147 return rc;
148
149 pAddress->fFlags |= DBGFADDRESS_FLAGS_VALID;
150
151 return VINF_SUCCESS;
152}
153
154
155/**
156 * Creates a mixed address from a flat address.
157 *
158 * @returns pAddress.
159 * @param pUVM The user mode VM handle.
160 * @param pAddress Where to store the mixed address.
161 * @param FlatPtr The flat pointer.
162 */
163VMMR3DECL(PDBGFADDRESS) DBGFR3AddrFromFlat(PUVM pUVM, PDBGFADDRESS pAddress, RTGCUINTPTR FlatPtr)
164{
165 UVM_ASSERT_VALID_EXT_RETURN(pUVM, NULL);
166 VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, NULL);
167 pAddress->Sel = DBGF_SEL_FLAT;
168 pAddress->off = FlatPtr;
169 pAddress->FlatPtr = FlatPtr;
170 pAddress->fFlags = DBGFADDRESS_FLAGS_FLAT | DBGFADDRESS_FLAGS_VALID;
171 return pAddress;
172}
173
174
175/**
176 * Creates a mixed address from a guest physical address.
177 *
178 * @returns pAddress.
179 * @param pUVM The user mode VM handle.
180 * @param pAddress Where to store the mixed address.
181 * @param PhysAddr The guest physical address.
182 */
183VMMR3DECL(PDBGFADDRESS) DBGFR3AddrFromPhys(PUVM pUVM, PDBGFADDRESS pAddress, RTGCPHYS PhysAddr)
184{
185 UVM_ASSERT_VALID_EXT_RETURN(pUVM, NULL);
186 pAddress->Sel = DBGF_SEL_FLAT;
187 pAddress->off = PhysAddr;
188 pAddress->FlatPtr = PhysAddr;
189 pAddress->fFlags = DBGFADDRESS_FLAGS_PHYS | DBGFADDRESS_FLAGS_VALID;
190 return pAddress;
191}
192
193
194/**
195 * Creates a mixed address from a flat host ring-0 address.
196 *
197 * @returns pAddress
198 * @param pAddress Where to store the mixed address.
199 * @param R0Ptr The host ring-0 address.
200 */
201VMMR3_INT_DECL(PDBGFADDRESS) DBGFR3AddrFromHostR0(PDBGFADDRESS pAddress, RTR0UINTPTR R0Ptr)
202{
203 pAddress->FlatPtr = R0Ptr;
204 pAddress->off = R0Ptr;
205 pAddress->fFlags = DBGFADDRESS_FLAGS_RING0 | DBGFADDRESS_FLAGS_VALID;
206 pAddress->Sel = DBGF_SEL_FLAT;
207 return pAddress;
208}
209
210
211/**
212 * Checks if the specified address is valid (checks the structure pointer too).
213 *
214 * @returns true if valid.
215 * @returns false if invalid.
216 * @param pUVM The user mode VM handle.
217 * @param pAddress The address to validate.
218 */
219VMMR3DECL(bool) DBGFR3AddrIsValid(PUVM pUVM, PCDBGFADDRESS pAddress)
220{
221 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
222 if (!RT_VALID_PTR(pAddress))
223 return false;
224 if (!DBGFADDRESS_IS_VALID(pAddress))
225 return false;
226 /* more? */
227 return true;
228}
229
230
231/**
232 * Called on the EMT for the VCpu.
233 *
234 * @returns VBox status code.
235 * @param pVCpu The cross context virtual CPU structure.
236 * @param pAddress The address.
237 * @param pGCPhys Where to return the physical address.
238 */
239static DECLCALLBACK(int) dbgfR3AddrToPhysOnVCpu(PVMCPU pVCpu, PCDBGFADDRESS pAddress, PRTGCPHYS pGCPhys)
240{
241 VMCPU_ASSERT_EMT(pVCpu);
242 PGMPTWALK Walk = { NIL_RTGCPTR, NIL_RTGCPHYS, NIL_RTGCPHYS, false };
243 int const rc = PGMGstGetPage(pVCpu, pAddress->FlatPtr, &Walk);
244 *pGCPhys = Walk.GCPhys;
245 return rc;
246}
247
248
249/**
250 * Converts an address to a guest physical address.
251 *
252 * @returns VBox status code.
253 * @retval VINF_SUCCESS
254 * @retval VERR_INVALID_PARAMETER if the address is invalid.
255 * @retval VERR_INVALID_STATE if the VM is being terminated or if the virtual
256 * CPU handle is invalid.
257 * @retval VERR_NOT_SUPPORTED is the type of address cannot be converted.
258 * @retval VERR_PAGE_NOT_PRESENT
259 * @retval VERR_PAGE_TABLE_NOT_PRESENT
260 * @retval VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT
261 * @retval VERR_PAGE_MAP_LEVEL4_NOT_PRESENT
262 *
263 * @param pUVM The user mode VM handle.
264 * @param idCpu The ID of the CPU context to convert virtual
265 * addresses.
266 * @param pAddress The address.
267 * @param pGCPhys Where to return the physical address.
268 */
269VMMR3DECL(int) DBGFR3AddrToPhys(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, PRTGCPHYS pGCPhys)
270{
271 /*
272 * Parameter validation.
273 */
274 AssertPtr(pGCPhys);
275 *pGCPhys = NIL_RTGCPHYS;
276 AssertPtr(pAddress);
277 AssertReturn(DBGFADDRESS_IS_VALID(pAddress), VERR_INVALID_PARAMETER);
278 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_STATE);
279 PVM pVM = pUVM->pVM;
280 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
281 AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_PARAMETER);
282
283 /*
284 * Convert by address type.
285 */
286 int rc;
287 if (pAddress->fFlags & DBGFADDRESS_FLAGS_PHYS)
288 {
289 *pGCPhys = pAddress->FlatPtr;
290 rc = VINF_SUCCESS;
291 }
292 else
293 {
294 PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu);
295 if (VMCPU_IS_EMT(pVCpu))
296 rc = dbgfR3AddrToPhysOnVCpu(pVCpu, pAddress, pGCPhys);
297 else
298 rc = VMR3ReqPriorityCallWaitU(pUVM, pVCpu->idCpu,
299 (PFNRT)dbgfR3AddrToPhysOnVCpu, 3, pVCpu, pAddress, pGCPhys);
300 }
301 return rc;
302}
303
304
305/**
306 * Converts an address to a host physical address.
307 *
308 * @returns VBox status code.
309 * @retval VINF_SUCCESS
310 * @retval VERR_INVALID_PARAMETER if the address is invalid.
311 * @retval VERR_INVALID_STATE if the VM is being terminated or if the virtual
312 * CPU handle is invalid.
313 * @retval VERR_NOT_SUPPORTED is the type of address cannot be converted.
314 * @retval VERR_PAGE_NOT_PRESENT
315 * @retval VERR_PAGE_TABLE_NOT_PRESENT
316 * @retval VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT
317 * @retval VERR_PAGE_MAP_LEVEL4_NOT_PRESENT
318 * @retval VERR_PGM_PHYS_PAGE_RESERVED
319 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS
320 *
321 * @param pUVM The user mode VM handle.
322 * @param idCpu The ID of the CPU context to convert virtual
323 * addresses.
324 * @param pAddress The address.
325 * @param pHCPhys Where to return the physical address.
326 */
327VMMR3DECL(int) DBGFR3AddrToHostPhys(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddress, PRTHCPHYS pHCPhys)
328{
329 /*
330 * Parameter validation.
331 */
332 AssertPtr(pHCPhys);
333 *pHCPhys = NIL_RTHCPHYS;
334 AssertPtr(pAddress);
335 AssertReturn(DBGFADDRESS_IS_VALID(pAddress), VERR_INVALID_PARAMETER);
336 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_STATE);
337 PVM pVM = pUVM->pVM;
338 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
339 AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_PARAMETER);
340
341 /*
342 * Convert it.
343 */
344 RTGCPHYS GCPhys;
345 int rc = DBGFR3AddrToPhys(pUVM, idCpu, pAddress, &GCPhys);
346 if (RT_SUCCESS(rc))
347 rc = PGMPhysGCPhys2HCPhys(pVM, pAddress->FlatPtr, pHCPhys);
348 return rc;
349}
350
351
352/**
353 * Called on the EMT for the VCpu.
354 *
355 * @returns VBox status code.
356 *
357 * @param pUVM The user mode VM handle.
358 * @param idCpu The ID of the CPU context.
359 * @param pAddress The address.
360 * @param fReadOnly Whether returning a read-only page is fine or not.
361 * @param ppvR3Ptr Where to return the address.
362 */
363static DECLCALLBACK(int) dbgfR3AddrToVolatileR3PtrOnVCpu(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddress, bool fReadOnly,
364 void **ppvR3Ptr)
365{
366 PVM pVM = pUVM->pVM;
367 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
368 Assert(idCpu == VMMGetCpuId(pVM));
369
370 /*
371 * This is a tad ugly, but it gets the job done.
372 */
373 int rc;
374 PGMPAGEMAPLOCK Lock;
375 if (pAddress->fFlags & DBGFADDRESS_FLAGS_PHYS)
376 {
377 if (fReadOnly)
378 rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, pAddress->FlatPtr, (void const **)ppvR3Ptr, &Lock);
379 else
380 rc = PGMPhysGCPhys2CCPtr(pVM, pAddress->FlatPtr, ppvR3Ptr, &Lock);
381 }
382 else
383 {
384 PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu);
385 if (fReadOnly)
386 rc = PGMPhysGCPtr2CCPtrReadOnly(pVCpu, pAddress->FlatPtr, (void const **)ppvR3Ptr, &Lock);
387 else
388 rc = PGMPhysGCPtr2CCPtr(pVCpu, pAddress->FlatPtr, ppvR3Ptr, &Lock);
389 }
390 if (RT_SUCCESS(rc))
391 PGMPhysReleasePageMappingLock(pVM, &Lock);
392 return rc;
393}
394
395
396
397
398/**
399 * Converts an address to a volatile host virtual address.
400 *
401 * @returns VBox status code.
402 * @retval VINF_SUCCESS
403 * @retval VERR_INVALID_PARAMETER if the address is invalid.
404 * @retval VERR_INVALID_STATE if the VM is being terminated or if the virtual
405 * CPU handle is invalid.
406 * @retval VERR_NOT_SUPPORTED is the type of address cannot be converted.
407 * @retval VERR_PAGE_NOT_PRESENT
408 * @retval VERR_PAGE_TABLE_NOT_PRESENT
409 * @retval VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT
410 * @retval VERR_PAGE_MAP_LEVEL4_NOT_PRESENT
411 * @retval VERR_PGM_PHYS_PAGE_RESERVED
412 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS
413 *
414 * @param pUVM The user mode VM handle.
415 * @param idCpu The ID of the CPU context to convert virtual
416 * addresses.
417 * @param pAddress The address.
418 * @param fReadOnly Whether returning a read-only page is fine or not.
419 * If set to thru the page may have to be made writable
420 * before we return.
421 * @param ppvR3Ptr Where to return the address.
422 */
423VMMR3DECL(int) DBGFR3AddrToVolatileR3Ptr(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddress, bool fReadOnly, void **ppvR3Ptr)
424{
425 /*
426 * Parameter validation.
427 */
428 AssertPtr(ppvR3Ptr);
429 *ppvR3Ptr = NULL;
430 AssertPtr(pAddress);
431 AssertReturn(DBGFADDRESS_IS_VALID(pAddress), VERR_INVALID_PARAMETER);
432 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_STATE);
433 AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_PARAMETER);
434
435 /*
436 * Convert it.
437 */
438 return VMR3ReqPriorityCallWaitU(pUVM, idCpu, (PFNRT)dbgfR3AddrToVolatileR3PtrOnVCpu, 5,
439 pUVM, idCpu, pAddress, fReadOnly, ppvR3Ptr);
440}
441
442
443/**
444 * Adds an offset to an address.
445 *
446 * @returns pAddress.
447 *
448 * @param pAddress The address.
449 * @param uAddend How much to add.
450 *
451 * @remarks No address space or segment limit checks are performed,
452 */
453VMMR3DECL(PDBGFADDRESS) DBGFR3AddrAdd(PDBGFADDRESS pAddress, RTGCUINTPTR uAddend)
454{
455 /*
456 * Parameter validation.
457 */
458 AssertPtrReturn(pAddress, NULL);
459 AssertReturn(DBGFADDRESS_IS_VALID(pAddress), NULL);
460
461 /*
462 * Add the stuff.
463 */
464 pAddress->off += uAddend;
465 pAddress->FlatPtr += uAddend;
466
467 return pAddress;
468}
469
470
471/**
472 * Subtracts an offset from an address.
473 *
474 * @returns VINF_SUCCESS on success.
475 *
476 * @param pAddress The address.
477 * @param uSubtrahend How much to subtract.
478 *
479 * @remarks No address space or segment limit checks are performed,
480 */
481VMMR3DECL(PDBGFADDRESS) DBGFR3AddrSub(PDBGFADDRESS pAddress, RTGCUINTPTR uSubtrahend)
482{
483 /*
484 * Parameter validation.
485 */
486 AssertPtrReturn(pAddress, NULL);
487 AssertReturn(DBGFADDRESS_IS_VALID(pAddress), NULL);
488
489 /*
490 * Add the stuff.
491 */
492 pAddress->off -= uSubtrahend;
493 pAddress->FlatPtr -= uSubtrahend;
494
495 return pAddress;
496}
497
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use