VirtualBox

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

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

Automated rebranding to Oracle copyright/license strings via filemuncher

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