VirtualBox

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

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

VM::cCPUs -> VM::cCpus so it matches all the other cCpus and aCpus members.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 15.6 KB
Line 
1/* $Id: DBGFAddr.cpp 22890 2009-09-09 23:11:31Z 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 {
280 PVMREQ pReq = NULL;
281 rc = VMR3ReqCall(pVCpu->pVMR3, pVCpu->idCpu, &pReq, RT_INDEFINITE_WAIT,
282 (PFNRT)dbgfR3AddrToPhysOnVCpu, 3, pVCpu, pAddress, pGCPhys);
283 if (RT_SUCCESS(rc))
284 {
285 rc = pReq->iStatus;
286 VMR3ReqFree(pReq);
287 }
288 }
289 }
290 return rc;
291}
292
293
294/**
295 * Converts an address to a host physical address.
296 *
297 * @returns VBox status code.
298 * @retval VINF_SUCCESS
299 * @retval VERR_INVALID_PARAMETER if the address is invalid.
300 * @retval VERR_INVALID_STATE if the VM is being terminated or if the virtual
301 * CPU handle is invalid.
302 * @retval VERR_NOT_SUPPORTED is the type of address cannot be converted.
303 * @retval VERR_PAGE_NOT_PRESENT
304 * @retval VERR_PAGE_TABLE_NOT_PRESENT
305 * @retval VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT
306 * @retval VERR_PAGE_MAP_LEVEL4_NOT_PRESENT
307 * @retval VERR_PGM_PHYS_PAGE_RESERVED
308 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS
309 *
310 * @param pVM The VM handle.
311 * @param idCpu The ID of the CPU context to convert virtual
312 * addresses.
313 * @param pAddress The address.
314 * @param pHCPhys Where to return the physical address.
315 */
316VMMR3DECL(int) DBGFR3AddrToHostPhys(PVM pVM, VMCPUID idCpu, PDBGFADDRESS pAddress, PRTHCPHYS pHCPhys)
317{
318 /*
319 * Parameter validation.
320 */
321 AssertPtr(pHCPhys);
322 *pHCPhys = NIL_RTHCPHYS;
323 AssertPtr(pAddress);
324 AssertReturn(DBGFADDRESS_IS_VALID(pAddress), VERR_INVALID_PARAMETER);
325 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_STATE);
326 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_PARAMETER);
327
328 /*
329 * Convert it if we can.
330 */
331 int rc;
332 if (pAddress->fFlags & DBGFADDRESS_FLAGS_HMA)
333 rc = VERR_NOT_SUPPORTED; /** @todo implement this */
334 else
335 {
336 RTGCPHYS GCPhys;
337 rc = DBGFR3AddrToPhys(pVM, idCpu, pAddress, &GCPhys);
338 if (RT_SUCCESS(rc))
339 rc = PGMPhysGCPhys2HCPhys(pVM, pAddress->FlatPtr, pHCPhys);
340 }
341 return rc;
342}
343
344
345/**
346 * Called on the EMT for the VCpu.
347 *
348 * @returns VBox status code.
349 *
350 * @param pVM The VM handle.
351 * @param idCpu The ID of the CPU context.
352 * @param pAddress The address.
353 * @param fReadOnly Whether returning a read-only page is fine or not.
354 * @param ppvR3Ptr Where to return the address.
355 */
356static DECLCALLBACK(int) dbgfR3AddrToVolatileR3PtrOnVCpu(PVM pVM, VMCPUID idCpu, PDBGFADDRESS pAddress, bool fReadOnly, void **ppvR3Ptr)
357{
358 Assert(idCpu == VMMGetCpuId(pVM));
359
360 int rc;
361 if (pAddress->fFlags & DBGFADDRESS_FLAGS_HMA)
362 {
363 rc = VERR_NOT_SUPPORTED; /** @todo create some dedicated errors for this stuff. */
364 /** @todo this may assert, create a debug version of this which doesn't. */
365 if (MMHyperIsInsideArea(pVM, pAddress->FlatPtr))
366 {
367 void *pv = MMHyperRCToCC(pVM, (RTRCPTR)pAddress->FlatPtr);
368 if (pv)
369 {
370 *ppvR3Ptr = pv;
371 rc = VINF_SUCCESS;
372 }
373 }
374 }
375 else
376 {
377 /*
378 * This is a tad ugly, but it gets the job done.
379 */
380 PGMPAGEMAPLOCK Lock;
381 if (pAddress->fFlags & DBGFADDRESS_FLAGS_PHYS)
382 {
383 if (fReadOnly)
384 rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, pAddress->FlatPtr, (void const **)ppvR3Ptr, &Lock);
385 else
386 rc = PGMPhysGCPhys2CCPtr(pVM, pAddress->FlatPtr, ppvR3Ptr, &Lock);
387 }
388 else
389 {
390 PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu);
391 if (fReadOnly)
392 rc = PGMPhysGCPtr2CCPtrReadOnly(pVCpu, pAddress->FlatPtr, (void const **)ppvR3Ptr, &Lock);
393 else
394 rc = PGMPhysGCPtr2CCPtr(pVCpu, pAddress->FlatPtr, ppvR3Ptr, &Lock);
395 }
396 if (RT_SUCCESS(rc))
397 PGMPhysReleasePageMappingLock(pVM, &Lock);
398 }
399 return rc;
400}
401
402
403
404
405/**
406 * Converts an address to a volatile host virtual address.
407 *
408 * @returns VBox status code.
409 * @retval VINF_SUCCESS
410 * @retval VERR_INVALID_PARAMETER if the address is invalid.
411 * @retval VERR_INVALID_STATE if the VM is being terminated or if the virtual
412 * CPU handle is invalid.
413 * @retval VERR_NOT_SUPPORTED is the type of address cannot be converted.
414 * @retval VERR_PAGE_NOT_PRESENT
415 * @retval VERR_PAGE_TABLE_NOT_PRESENT
416 * @retval VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT
417 * @retval VERR_PAGE_MAP_LEVEL4_NOT_PRESENT
418 * @retval VERR_PGM_PHYS_PAGE_RESERVED
419 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS
420 *
421 * @param pVM The VM handle.
422 * @param idCpu The ID of the CPU context to convert virtual
423 * addresses.
424 * @param pAddress The address.
425 * @param fReadOnly Whether returning a read-only page is fine or not.
426 * If set to thru the page may have to be made writable
427 * before we return.
428 * @param ppvR3Ptr Where to return the address.
429 */
430VMMR3DECL(int) DBGFR3AddrToVolatileR3Ptr(PVM pVM, VMCPUID idCpu, PDBGFADDRESS pAddress, bool fReadOnly, void **ppvR3Ptr)
431{
432 /*
433 * Parameter validation.
434 */
435 AssertPtr(ppvR3Ptr);
436 *ppvR3Ptr = NULL;
437 AssertPtr(pAddress);
438 AssertReturn(DBGFADDRESS_IS_VALID(pAddress), VERR_INVALID_PARAMETER);
439 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_STATE);
440 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_PARAMETER);
441
442 /*
443 * Convert it.
444 */
445 PVMREQ pReq = NULL;
446 int rc = VMR3ReqCall(pVM, idCpu, &pReq, RT_INDEFINITE_WAIT,
447 (PFNRT)dbgfR3AddrToVolatileR3PtrOnVCpu, 5, pVM, idCpu, pAddress, fReadOnly, ppvR3Ptr);
448 if (RT_SUCCESS(rc))
449 {
450 rc = pReq->iStatus;
451 VMR3ReqFree(pReq);
452 }
453
454 return rc;
455}
456
457
458/**
459 * Adds an offset to an address.
460 *
461 * @returns pAddress.
462 *
463 * @param pAddress The address.
464 * @param uAddend How much to add.
465 *
466 * @remarks No address space or segment limit checks are performed,
467 */
468VMMR3DECL(PDBGFADDRESS) DBGFR3AddrAdd(PDBGFADDRESS pAddress, RTGCUINTPTR uAddend)
469{
470 /*
471 * Parameter validation.
472 */
473 AssertPtrReturn(pAddress, NULL);
474 AssertReturn(DBGFADDRESS_IS_VALID(pAddress), NULL);
475
476 /*
477 * Add the stuff.
478 */
479 pAddress->off += uAddend;
480 pAddress->FlatPtr += uAddend;
481
482 return pAddress;
483}
484
485
486/**
487 * Subtracts an offset from an address.
488 *
489 * @returns VINF_SUCCESS on success.
490 *
491 * @param pAddress The address.
492 * @param uSubtrahend How much to subtract.
493 *
494 * @remarks No address space or segment limit checks are performed,
495 */
496VMMR3DECL(PDBGFADDRESS) DBGFR3AddrSub(PDBGFADDRESS pAddress, RTGCUINTPTR uSubtrahend)
497{
498 /*
499 * Parameter validation.
500 */
501 AssertPtrReturn(pAddress, NULL);
502 AssertReturn(DBGFADDRESS_IS_VALID(pAddress), NULL);
503
504 /*
505 * Add the stuff.
506 */
507 pAddress->off -= uSubtrahend;
508 pAddress->FlatPtr -= uSubtrahend;
509
510 return pAddress;
511}
512
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