VirtualBox

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

Last change on this file since 78254 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

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