VirtualBox

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

Last change on this file since 62596 was 62478, checked in by vboxsync, 8 years ago

(C) 2016

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