VirtualBox

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

Last change on this file since 102557 was 98103, checked in by vboxsync, 2 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 15.6 KB
Line 
1/* $Id: DBGFAddr.cpp 98103 2023-01-17 14:15:46Z 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 /* This is just a wrapper because we cannot pass FlatPtr thru VMR3ReqCall directly. */
243 PGMPTWALK Walk;
244 int const rc = PGMGstGetPage(pVCpu, pAddress->FlatPtr, &Walk);
245 *pGCPhys = Walk.GCPhys;
246 return rc;
247}
248
249
250/**
251 * Converts an address to a guest physical address.
252 *
253 * @returns VBox status code.
254 * @retval VINF_SUCCESS
255 * @retval VERR_INVALID_PARAMETER if the address is invalid.
256 * @retval VERR_INVALID_STATE if the VM is being terminated or if the virtual
257 * CPU handle is invalid.
258 * @retval VERR_NOT_SUPPORTED is the type of address cannot be converted.
259 * @retval VERR_PAGE_NOT_PRESENT
260 * @retval VERR_PAGE_TABLE_NOT_PRESENT
261 * @retval VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT
262 * @retval VERR_PAGE_MAP_LEVEL4_NOT_PRESENT
263 *
264 * @param pUVM The user mode VM handle.
265 * @param idCpu The ID of the CPU context to convert virtual
266 * addresses.
267 * @param pAddress The address.
268 * @param pGCPhys Where to return the physical address.
269 */
270VMMR3DECL(int) DBGFR3AddrToPhys(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, PRTGCPHYS pGCPhys)
271{
272 /*
273 * Parameter validation.
274 */
275 AssertPtr(pGCPhys);
276 *pGCPhys = NIL_RTGCPHYS;
277 AssertPtr(pAddress);
278 AssertReturn(DBGFADDRESS_IS_VALID(pAddress), VERR_INVALID_PARAMETER);
279 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_STATE);
280 PVM pVM = pUVM->pVM;
281 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
282 AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_PARAMETER);
283
284 /*
285 * Convert by address type.
286 */
287 int rc;
288 if (pAddress->fFlags & DBGFADDRESS_FLAGS_PHYS)
289 {
290 *pGCPhys = pAddress->FlatPtr;
291 rc = VINF_SUCCESS;
292 }
293 else
294 {
295 PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu);
296 if (VMCPU_IS_EMT(pVCpu))
297 rc = dbgfR3AddrToPhysOnVCpu(pVCpu, pAddress, pGCPhys);
298 else
299 rc = VMR3ReqPriorityCallWaitU(pUVM, pVCpu->idCpu,
300 (PFNRT)dbgfR3AddrToPhysOnVCpu, 3, pVCpu, pAddress, pGCPhys);
301 }
302 return rc;
303}
304
305
306/**
307 * Converts an address to a host physical address.
308 *
309 * @returns VBox status code.
310 * @retval VINF_SUCCESS
311 * @retval VERR_INVALID_PARAMETER if the address is invalid.
312 * @retval VERR_INVALID_STATE if the VM is being terminated or if the virtual
313 * CPU handle is invalid.
314 * @retval VERR_NOT_SUPPORTED is the type of address cannot be converted.
315 * @retval VERR_PAGE_NOT_PRESENT
316 * @retval VERR_PAGE_TABLE_NOT_PRESENT
317 * @retval VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT
318 * @retval VERR_PAGE_MAP_LEVEL4_NOT_PRESENT
319 * @retval VERR_PGM_PHYS_PAGE_RESERVED
320 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS
321 *
322 * @param pUVM The user mode VM handle.
323 * @param idCpu The ID of the CPU context to convert virtual
324 * addresses.
325 * @param pAddress The address.
326 * @param pHCPhys Where to return the physical address.
327 */
328VMMR3DECL(int) DBGFR3AddrToHostPhys(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddress, PRTHCPHYS pHCPhys)
329{
330 /*
331 * Parameter validation.
332 */
333 AssertPtr(pHCPhys);
334 *pHCPhys = NIL_RTHCPHYS;
335 AssertPtr(pAddress);
336 AssertReturn(DBGFADDRESS_IS_VALID(pAddress), VERR_INVALID_PARAMETER);
337 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_STATE);
338 PVM pVM = pUVM->pVM;
339 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
340 AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_PARAMETER);
341
342 /*
343 * Convert it.
344 */
345 RTGCPHYS GCPhys;
346 int rc = DBGFR3AddrToPhys(pUVM, idCpu, pAddress, &GCPhys);
347 if (RT_SUCCESS(rc))
348 rc = PGMPhysGCPhys2HCPhys(pVM, pAddress->FlatPtr, pHCPhys);
349 return rc;
350}
351
352
353/**
354 * Called on the EMT for the VCpu.
355 *
356 * @returns VBox status code.
357 *
358 * @param pUVM The user mode VM handle.
359 * @param idCpu The ID of the CPU context.
360 * @param pAddress The address.
361 * @param fReadOnly Whether returning a read-only page is fine or not.
362 * @param ppvR3Ptr Where to return the address.
363 */
364static DECLCALLBACK(int) dbgfR3AddrToVolatileR3PtrOnVCpu(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddress, bool fReadOnly,
365 void **ppvR3Ptr)
366{
367 PVM pVM = pUVM->pVM;
368 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
369 Assert(idCpu == VMMGetCpuId(pVM));
370
371 /*
372 * This is a tad ugly, but it gets the job done.
373 */
374 int rc;
375 PGMPAGEMAPLOCK Lock;
376 if (pAddress->fFlags & DBGFADDRESS_FLAGS_PHYS)
377 {
378 if (fReadOnly)
379 rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, pAddress->FlatPtr, (void const **)ppvR3Ptr, &Lock);
380 else
381 rc = PGMPhysGCPhys2CCPtr(pVM, pAddress->FlatPtr, ppvR3Ptr, &Lock);
382 }
383 else
384 {
385 PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu);
386 if (fReadOnly)
387 rc = PGMPhysGCPtr2CCPtrReadOnly(pVCpu, pAddress->FlatPtr, (void const **)ppvR3Ptr, &Lock);
388 else
389 rc = PGMPhysGCPtr2CCPtr(pVCpu, pAddress->FlatPtr, ppvR3Ptr, &Lock);
390 }
391 if (RT_SUCCESS(rc))
392 PGMPhysReleasePageMappingLock(pVM, &Lock);
393 return rc;
394}
395
396
397
398
399/**
400 * Converts an address to a volatile host virtual address.
401 *
402 * @returns VBox status code.
403 * @retval VINF_SUCCESS
404 * @retval VERR_INVALID_PARAMETER if the address is invalid.
405 * @retval VERR_INVALID_STATE if the VM is being terminated or if the virtual
406 * CPU handle is invalid.
407 * @retval VERR_NOT_SUPPORTED is the type of address cannot be converted.
408 * @retval VERR_PAGE_NOT_PRESENT
409 * @retval VERR_PAGE_TABLE_NOT_PRESENT
410 * @retval VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT
411 * @retval VERR_PAGE_MAP_LEVEL4_NOT_PRESENT
412 * @retval VERR_PGM_PHYS_PAGE_RESERVED
413 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS
414 *
415 * @param pUVM The user mode VM handle.
416 * @param idCpu The ID of the CPU context to convert virtual
417 * addresses.
418 * @param pAddress The address.
419 * @param fReadOnly Whether returning a read-only page is fine or not.
420 * If set to thru the page may have to be made writable
421 * before we return.
422 * @param ppvR3Ptr Where to return the address.
423 */
424VMMR3DECL(int) DBGFR3AddrToVolatileR3Ptr(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddress, bool fReadOnly, void **ppvR3Ptr)
425{
426 /*
427 * Parameter validation.
428 */
429 AssertPtr(ppvR3Ptr);
430 *ppvR3Ptr = NULL;
431 AssertPtr(pAddress);
432 AssertReturn(DBGFADDRESS_IS_VALID(pAddress), VERR_INVALID_PARAMETER);
433 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_STATE);
434 AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_PARAMETER);
435
436 /*
437 * Convert it.
438 */
439 return VMR3ReqPriorityCallWaitU(pUVM, idCpu, (PFNRT)dbgfR3AddrToVolatileR3PtrOnVCpu, 5,
440 pUVM, idCpu, pAddress, fReadOnly, ppvR3Ptr);
441}
442
443
444/**
445 * Adds an offset to an address.
446 *
447 * @returns pAddress.
448 *
449 * @param pAddress The address.
450 * @param uAddend How much to add.
451 *
452 * @remarks No address space or segment limit checks are performed,
453 */
454VMMR3DECL(PDBGFADDRESS) DBGFR3AddrAdd(PDBGFADDRESS pAddress, RTGCUINTPTR uAddend)
455{
456 /*
457 * Parameter validation.
458 */
459 AssertPtrReturn(pAddress, NULL);
460 AssertReturn(DBGFADDRESS_IS_VALID(pAddress), NULL);
461
462 /*
463 * Add the stuff.
464 */
465 pAddress->off += uAddend;
466 pAddress->FlatPtr += uAddend;
467
468 return pAddress;
469}
470
471
472/**
473 * Subtracts an offset from an address.
474 *
475 * @returns VINF_SUCCESS on success.
476 *
477 * @param pAddress The address.
478 * @param uSubtrahend How much to subtract.
479 *
480 * @remarks No address space or segment limit checks are performed,
481 */
482VMMR3DECL(PDBGFADDRESS) DBGFR3AddrSub(PDBGFADDRESS pAddress, RTGCUINTPTR uSubtrahend)
483{
484 /*
485 * Parameter validation.
486 */
487 AssertPtrReturn(pAddress, NULL);
488 AssertReturn(DBGFADDRESS_IS_VALID(pAddress), NULL);
489
490 /*
491 * Add the stuff.
492 */
493 pAddress->off -= uSubtrahend;
494 pAddress->FlatPtr -= uSubtrahend;
495
496 return pAddress;
497}
498
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