VirtualBox

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

Last change on this file since 91281 was 90784, checked in by vboxsync, 3 years ago

VMM: VALID_PTR -> RT_VALID_PTR.

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