VirtualBox

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

Last change on this file since 45865 was 45753, checked in by vboxsync, 12 years ago

Don't call MMHyperIsInsideArea if we're using HM to execute code, it will return bogus results!

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