VirtualBox

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

Last change on this file since 57166 was 56287, checked in by vboxsync, 10 years ago

VMM: Updated (C) year.

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