VirtualBox

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

Last change on this file since 45026 was 44528, checked in by vboxsync, 12 years ago

header (C) fixes

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