VirtualBox

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

Last change on this file since 25046 was 23012, checked in by vboxsync, 15 years ago

VMM,Devices,Main: VMR3ReqCall w/ RT_INDEFINITE_WAIT -> VMR3ReqCallWait.

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