VirtualBox

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

Last change on this file since 44360 was 41965, checked in by vboxsync, 12 years ago

VMM: ran scm. Mostly svn:keywords changes (adding Revision).

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