VirtualBox

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

Last change on this file since 92508 was 92426, checked in by vboxsync, 3 years ago

VMM: Nested VMX: bugref:10092 Refactor PGMGstGetPage and related API and functions to pass more info back to callers on page walk failures.

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