VirtualBox

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

Last change on this file since 32953 was 30493, checked in by vboxsync, 14 years ago

Demoted some PGM apis to internal only.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 15.0 KB
Line 
1/* $Id: DBGFAddr.cpp 30493 2010-06-29 11:59:47Z 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/dbgf.h>
24#include <VBox/pgm.h>
25#include <VBox/selm.h>
26#include <VBox/mm.h>
27#include "DBGFInternal.h"
28#include <VBox/vm.h>
29#include <VBox/param.h>
30#include <VBox/err.h>
31#include <VBox/log.h>
32#include <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 The VM handle.
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 The VM handle.
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 The VM handle.
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 The VM handle.
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 The VM handle.
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 pAddress->Sel = DBGF_SEL_FLAT;
185 pAddress->off = PhysAddr;
186 pAddress->FlatPtr = PhysAddr;
187 pAddress->fFlags = DBGFADDRESS_FLAGS_PHYS | DBGFADDRESS_FLAGS_VALID;
188 return pAddress;
189}
190
191
192/**
193 * Checks if the specified address is valid (checks the structure pointer too).
194 *
195 * @returns true if valid.
196 * @returns false if invalid.
197 * @param pVM The VM handle.
198 * @param pAddress The address to validate.
199 */
200VMMR3DECL(bool) DBGFR3AddrIsValid(PVM pVM, PCDBGFADDRESS pAddress)
201{
202 if (!VALID_PTR(pAddress))
203 return false;
204 if (!DBGFADDRESS_IS_VALID(pAddress))
205 return false;
206 /* more? */
207 return true;
208}
209
210
211/**
212 * Called on the EMT for the VCpu.
213 *
214 * @returns VBox status code.
215 * @param pVCpu The virtual CPU handle.
216 * @param pAddress The address.
217 * @param pGCPhys Where to return the physical address.
218 */
219static DECLCALLBACK(int) dbgfR3AddrToPhysOnVCpu(PVMCPU pVCpu, PDBGFADDRESS pAddress, PRTGCPHYS pGCPhys)
220{
221 VMCPU_ASSERT_EMT(pVCpu);
222 /* This is just a wrapper because we cannot pass FlatPtr thru VMR3ReqCall directly. */
223 return PGMGstGetPage(pVCpu, pAddress->FlatPtr, NULL, pGCPhys);
224}
225
226
227/**
228 * Converts an address to a guest physical address.
229 *
230 * @returns VBox status code.
231 * @retval VINF_SUCCESS
232 * @retval VERR_INVALID_PARAMETER if the address is invalid.
233 * @retval VERR_INVALID_STATE if the VM is being terminated or if the virtual
234 * CPU handle is invalid.
235 * @retval VERR_NOT_SUPPORTED is the type of address cannot be converted.
236 * @retval VERR_PAGE_NOT_PRESENT
237 * @retval VERR_PAGE_TABLE_NOT_PRESENT
238 * @retval VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT
239 * @retval VERR_PAGE_MAP_LEVEL4_NOT_PRESENT
240 *
241 * @param pVM The VM handle.
242 * @param idCpu The ID of the CPU context to convert virtual
243 * addresses.
244 * @param pAddress The address.
245 * @param pGCPhys Where to return the physical address.
246 */
247VMMR3DECL(int) DBGFR3AddrToPhys(PVM pVM, VMCPUID idCpu, PDBGFADDRESS pAddress, PRTGCPHYS pGCPhys)
248{
249 /*
250 * Parameter validation.
251 */
252 AssertPtr(pGCPhys);
253 *pGCPhys = NIL_RTGCPHYS;
254 AssertPtr(pAddress);
255 AssertReturn(DBGFADDRESS_IS_VALID(pAddress), VERR_INVALID_PARAMETER);
256 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_STATE);
257 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_PARAMETER);
258
259 /*
260 * Convert by address type.
261 */
262 int rc;
263 if (pAddress->fFlags & DBGFADDRESS_FLAGS_HMA)
264 rc = VERR_NOT_SUPPORTED;
265 else if (pAddress->fFlags & DBGFADDRESS_FLAGS_PHYS)
266 {
267 *pGCPhys = pAddress->FlatPtr;
268 rc = VINF_SUCCESS;
269 }
270 else
271 {
272 PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu);
273 if (VMCPU_IS_EMT(pVCpu))
274 rc = dbgfR3AddrToPhysOnVCpu(pVCpu, pAddress, pGCPhys);
275 else
276 rc = VMR3ReqCallWait(pVCpu->pVMR3, pVCpu->idCpu,
277 (PFNRT)dbgfR3AddrToPhysOnVCpu, 3, pVCpu, pAddress, pGCPhys);
278 }
279 return rc;
280}
281
282
283/**
284 * Converts an address to a host physical address.
285 *
286 * @returns VBox status code.
287 * @retval VINF_SUCCESS
288 * @retval VERR_INVALID_PARAMETER if the address is invalid.
289 * @retval VERR_INVALID_STATE if the VM is being terminated or if the virtual
290 * CPU handle is invalid.
291 * @retval VERR_NOT_SUPPORTED is the type of address cannot be converted.
292 * @retval VERR_PAGE_NOT_PRESENT
293 * @retval VERR_PAGE_TABLE_NOT_PRESENT
294 * @retval VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT
295 * @retval VERR_PAGE_MAP_LEVEL4_NOT_PRESENT
296 * @retval VERR_PGM_PHYS_PAGE_RESERVED
297 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS
298 *
299 * @param pVM The VM handle.
300 * @param idCpu The ID of the CPU context to convert virtual
301 * addresses.
302 * @param pAddress The address.
303 * @param pHCPhys Where to return the physical address.
304 */
305VMMR3DECL(int) DBGFR3AddrToHostPhys(PVM pVM, VMCPUID idCpu, PDBGFADDRESS pAddress, PRTHCPHYS pHCPhys)
306{
307 /*
308 * Parameter validation.
309 */
310 AssertPtr(pHCPhys);
311 *pHCPhys = NIL_RTHCPHYS;
312 AssertPtr(pAddress);
313 AssertReturn(DBGFADDRESS_IS_VALID(pAddress), VERR_INVALID_PARAMETER);
314 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_STATE);
315 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_PARAMETER);
316
317 /*
318 * Convert it if we can.
319 */
320 int rc;
321 if (pAddress->fFlags & DBGFADDRESS_FLAGS_HMA)
322 rc = VERR_NOT_SUPPORTED; /** @todo implement this */
323 else
324 {
325 RTGCPHYS GCPhys;
326 rc = DBGFR3AddrToPhys(pVM, idCpu, pAddress, &GCPhys);
327 if (RT_SUCCESS(rc))
328 rc = PGMPhysGCPhys2HCPhys(pVM, pAddress->FlatPtr, pHCPhys);
329 }
330 return rc;
331}
332
333
334/**
335 * Called on the EMT for the VCpu.
336 *
337 * @returns VBox status code.
338 *
339 * @param pVM The VM handle.
340 * @param idCpu The ID of the CPU context.
341 * @param pAddress The address.
342 * @param fReadOnly Whether returning a read-only page is fine or not.
343 * @param ppvR3Ptr Where to return the address.
344 */
345static DECLCALLBACK(int) dbgfR3AddrToVolatileR3PtrOnVCpu(PVM pVM, VMCPUID idCpu, PDBGFADDRESS pAddress, bool fReadOnly, void **ppvR3Ptr)
346{
347 Assert(idCpu == VMMGetCpuId(pVM));
348
349 int rc;
350 if (pAddress->fFlags & DBGFADDRESS_FLAGS_HMA)
351 {
352 rc = VERR_NOT_SUPPORTED; /** @todo create some dedicated errors for this stuff. */
353 /** @todo this may assert, create a debug version of this which doesn't. */
354 if (MMHyperIsInsideArea(pVM, pAddress->FlatPtr))
355 {
356 void *pv = MMHyperRCToCC(pVM, (RTRCPTR)pAddress->FlatPtr);
357 if (pv)
358 {
359 *ppvR3Ptr = pv;
360 rc = VINF_SUCCESS;
361 }
362 }
363 }
364 else
365 {
366 /*
367 * This is a tad ugly, but it gets the job done.
368 */
369 PGMPAGEMAPLOCK Lock;
370 if (pAddress->fFlags & DBGFADDRESS_FLAGS_PHYS)
371 {
372 if (fReadOnly)
373 rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, pAddress->FlatPtr, (void const **)ppvR3Ptr, &Lock);
374 else
375 rc = PGMPhysGCPhys2CCPtr(pVM, pAddress->FlatPtr, ppvR3Ptr, &Lock);
376 }
377 else
378 {
379 PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu);
380 if (fReadOnly)
381 rc = PGMPhysGCPtr2CCPtrReadOnly(pVCpu, pAddress->FlatPtr, (void const **)ppvR3Ptr, &Lock);
382 else
383 rc = PGMPhysGCPtr2CCPtr(pVCpu, pAddress->FlatPtr, ppvR3Ptr, &Lock);
384 }
385 if (RT_SUCCESS(rc))
386 PGMPhysReleasePageMappingLock(pVM, &Lock);
387 }
388 return rc;
389}
390
391
392
393
394/**
395 * Converts an address to a volatile host virtual address.
396 *
397 * @returns VBox status code.
398 * @retval VINF_SUCCESS
399 * @retval VERR_INVALID_PARAMETER if the address is invalid.
400 * @retval VERR_INVALID_STATE if the VM is being terminated or if the virtual
401 * CPU handle is invalid.
402 * @retval VERR_NOT_SUPPORTED is the type of address cannot be converted.
403 * @retval VERR_PAGE_NOT_PRESENT
404 * @retval VERR_PAGE_TABLE_NOT_PRESENT
405 * @retval VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT
406 * @retval VERR_PAGE_MAP_LEVEL4_NOT_PRESENT
407 * @retval VERR_PGM_PHYS_PAGE_RESERVED
408 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS
409 *
410 * @param pVM The VM handle.
411 * @param idCpu The ID of the CPU context to convert virtual
412 * addresses.
413 * @param pAddress The address.
414 * @param fReadOnly Whether returning a read-only page is fine or not.
415 * If set to thru the page may have to be made writable
416 * before we return.
417 * @param ppvR3Ptr Where to return the address.
418 */
419VMMR3DECL(int) DBGFR3AddrToVolatileR3Ptr(PVM pVM, VMCPUID idCpu, PDBGFADDRESS pAddress, bool fReadOnly, void **ppvR3Ptr)
420{
421 /*
422 * Parameter validation.
423 */
424 AssertPtr(ppvR3Ptr);
425 *ppvR3Ptr = NULL;
426 AssertPtr(pAddress);
427 AssertReturn(DBGFADDRESS_IS_VALID(pAddress), VERR_INVALID_PARAMETER);
428 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_STATE);
429 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_PARAMETER);
430
431 /*
432 * Convert it.
433 */
434 return VMR3ReqCallWait(pVM, idCpu, (PFNRT)dbgfR3AddrToVolatileR3PtrOnVCpu, 5, pVM, idCpu, pAddress, fReadOnly, ppvR3Ptr);
435}
436
437
438/**
439 * Adds an offset to an address.
440 *
441 * @returns pAddress.
442 *
443 * @param pAddress The address.
444 * @param uAddend How much to add.
445 *
446 * @remarks No address space or segment limit checks are performed,
447 */
448VMMR3DECL(PDBGFADDRESS) DBGFR3AddrAdd(PDBGFADDRESS pAddress, RTGCUINTPTR uAddend)
449{
450 /*
451 * Parameter validation.
452 */
453 AssertPtrReturn(pAddress, NULL);
454 AssertReturn(DBGFADDRESS_IS_VALID(pAddress), NULL);
455
456 /*
457 * Add the stuff.
458 */
459 pAddress->off += uAddend;
460 pAddress->FlatPtr += uAddend;
461
462 return pAddress;
463}
464
465
466/**
467 * Subtracts an offset from an address.
468 *
469 * @returns VINF_SUCCESS on success.
470 *
471 * @param pAddress The address.
472 * @param uSubtrahend How much to subtract.
473 *
474 * @remarks No address space or segment limit checks are performed,
475 */
476VMMR3DECL(PDBGFADDRESS) DBGFR3AddrSub(PDBGFADDRESS pAddress, RTGCUINTPTR uSubtrahend)
477{
478 /*
479 * Parameter validation.
480 */
481 AssertPtrReturn(pAddress, NULL);
482 AssertReturn(DBGFADDRESS_IS_VALID(pAddress), NULL);
483
484 /*
485 * Add the stuff.
486 */
487 pAddress->off -= uSubtrahend;
488 pAddress->FlatPtr -= uSubtrahend;
489
490 return pAddress;
491}
492
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