VirtualBox

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

Last change on this file since 79345 was 78434, checked in by vboxsync, 6 years ago

VMM: Build fixes for VBOX_WITH_RAW_MODE= on windows.

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