VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/PGMSharedPage.cpp@ 39944

Last change on this file since 39944 was 39084, checked in by vboxsync, 13 years ago

VMM: -Wunused-parameter on mac.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.7 KB
Line 
1/* $Id: PGMSharedPage.cpp 39084 2011-10-22 00:37:15Z vboxsync $ */
2/** @file
3 * PGM - Page Manager and Monitor, Shared page handling
4 */
5
6/*
7 * Copyright (C) 2006-2011 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_PGM_SHARED
23#include <VBox/vmm/pgm.h>
24#include <VBox/vmm/stam.h>
25#include "PGMInternal.h"
26#include <VBox/vmm/vm.h>
27#include <VBox/sup.h>
28#include <VBox/param.h>
29#include <VBox/err.h>
30#include <VBox/log.h>
31#include <iprt/asm.h>
32#include <iprt/assert.h>
33#include <iprt/mem.h>
34#include <iprt/string.h>
35
36#include "PGMInline.h"
37
38
39/*******************************************************************************
40* Global Variables *
41*******************************************************************************/
42#if defined(VBOX_WITH_PAGE_SHARING) && defined(VBOX_STRICT)
43/** Keep a copy of all registered shared modules for the .pgmcheckduppages debugger command. */
44static PGMMREGISTERSHAREDMODULEREQ g_apSharedModules[512] = {0};
45static unsigned g_cSharedModules = 0;
46#endif
47
48
49/**
50 * Registers a new shared module for the VM
51 *
52 * @returns VBox status code.
53 * @param pVM VM handle
54 * @param enmGuestOS Guest OS type
55 * @param pszModuleName Module name
56 * @param pszVersion Module version
57 * @param GCBaseAddr Module base address
58 * @param cbModule Module size
59 * @param cRegions Number of shared region descriptors
60 * @param pRegions Shared region(s)
61 */
62VMMR3DECL(int) PGMR3SharedModuleRegister(PVM pVM, VBOXOSFAMILY enmGuestOS, char *pszModuleName, char *pszVersion,
63 RTGCPTR GCBaseAddr, uint32_t cbModule, unsigned cRegions,
64 VMMDEVSHAREDREGIONDESC *pRegions)
65{
66#ifdef VBOX_WITH_PAGE_SHARING
67 Log(("PGMR3SharedModuleRegister family=%d name=%s version=%s base=%RGv size=%x cRegions=%d\n", enmGuestOS, pszModuleName, pszVersion, GCBaseAddr, cbModule, cRegions));
68
69 /* Sanity check. */
70 AssertReturn(cRegions < VMMDEVSHAREDREGIONDESC_MAX, VERR_INVALID_PARAMETER);
71
72 PGMMREGISTERSHAREDMODULEREQ pReq;
73 pReq = (PGMMREGISTERSHAREDMODULEREQ)RTMemAllocZ(RT_OFFSETOF(GMMREGISTERSHAREDMODULEREQ, aRegions[cRegions]));
74 AssertReturn(pReq, VERR_NO_MEMORY);
75
76 pReq->enmGuestOS = enmGuestOS;
77 pReq->GCBaseAddr = GCBaseAddr;
78 pReq->cbModule = cbModule;
79 pReq->cRegions = cRegions;
80 for (unsigned i = 0; i < cRegions; i++)
81 pReq->aRegions[i] = pRegions[i];
82
83 if ( RTStrCopy(pReq->szName, sizeof(pReq->szName), pszModuleName) != VINF_SUCCESS
84 || RTStrCopy(pReq->szVersion, sizeof(pReq->szVersion), pszVersion) != VINF_SUCCESS)
85 {
86 RTMemFree(pReq);
87 return VERR_BUFFER_OVERFLOW;
88 }
89
90 int rc = GMMR3RegisterSharedModule(pVM, pReq);
91# ifdef VBOX_STRICT
92 if (rc == VINF_SUCCESS)
93 {
94 PGMMREGISTERSHAREDMODULEREQ *ppSharedModule = NULL;
95
96 if (g_cSharedModules < RT_ELEMENTS(g_apSharedModules))
97 {
98 for (unsigned i = 0; i < RT_ELEMENTS(g_apSharedModules); i++)
99 {
100 if (g_apSharedModules[i] == NULL)
101 {
102 ppSharedModule = &g_apSharedModules[i];
103 break;
104 }
105 }
106 Assert(ppSharedModule);
107
108 if (ppSharedModule)
109 {
110 size_t const cbSharedModule = RT_OFFSETOF(GMMREGISTERSHAREDMODULEREQ, aRegions[cRegions]);
111 *ppSharedModule = (PGMMREGISTERSHAREDMODULEREQ)RTMemDup(pReq, cbSharedModule);
112 g_cSharedModules++;
113 }
114 }
115 }
116# endif /* VBOX_STRICT */
117
118 RTMemFree(pReq);
119 Assert(rc == VINF_SUCCESS || rc == VINF_PGM_SHARED_MODULE_COLLISION || rc == VINF_PGM_SHARED_MODULE_ALREADY_REGISTERED);
120 if (RT_FAILURE(rc))
121 return rc;
122
123 return VINF_SUCCESS;
124#else /* !VBOX_WITH_PAGE_SHARING */
125
126 NOREF(pVM); NOREF(enmGuestOS); NOREF(pszModuleName); NOREF(pszVersion); NOREF(GCBaseAddr);
127 NOREF(cbModule); NOREF(cRegions); NOREF(pRegions);
128 return VERR_NOT_IMPLEMENTED;
129#endif /* !VBOX_WITH_PAGE_SHARING */
130}
131
132
133/**
134 * Unregisters a shared module for the VM
135 *
136 * @returns VBox status code.
137 * @param pVM VM handle
138 * @param pszModuleName Module name
139 * @param pszVersion Module version
140 * @param GCBaseAddr Module base address
141 * @param cbModule Module size
142 */
143VMMR3DECL(int) PGMR3SharedModuleUnregister(PVM pVM, char *pszModuleName, char *pszVersion, RTGCPTR GCBaseAddr, uint32_t cbModule)
144{
145#ifdef VBOX_WITH_PAGE_SHARING
146 PGMMUNREGISTERSHAREDMODULEREQ pReq;
147
148 Log(("PGMR3SharedModuleUnregister name=%s version=%s base=%RGv size=%x\n", pszModuleName, pszVersion, GCBaseAddr, cbModule));
149
150 pReq = (PGMMUNREGISTERSHAREDMODULEREQ)RTMemAllocZ(sizeof(*pReq));
151 AssertReturn(pReq, VERR_NO_MEMORY);
152
153 pReq->GCBaseAddr = GCBaseAddr;
154 pReq->cbModule = cbModule;
155
156 if ( RTStrCopy(pReq->szName, sizeof(pReq->szName), pszModuleName) != VINF_SUCCESS
157 || RTStrCopy(pReq->szVersion, sizeof(pReq->szVersion), pszVersion) != VINF_SUCCESS)
158 {
159 RTMemFree(pReq);
160 return VERR_BUFFER_OVERFLOW;
161 }
162 int rc = GMMR3UnregisterSharedModule(pVM, pReq);
163 RTMemFree(pReq);
164
165# ifdef VBOX_STRICT
166 for (unsigned i = 0; i < g_cSharedModules; i++)
167 {
168 if ( g_apSharedModules[i]
169 && !strcmp(g_apSharedModules[i]->szName, pszModuleName)
170 && !strcmp(g_apSharedModules[i]->szVersion, pszVersion))
171 {
172 RTMemFree(g_apSharedModules[i]);
173 g_apSharedModules[i] = NULL;
174 g_cSharedModules--;
175 break;
176 }
177 }
178# endif /* VBOX_STRICT */
179 return rc;
180#else /* !VBOX_WITH_PAGE_SHARING */
181
182 NOREF(pVM); NOREF(pszModuleName); NOREF(pszVersion); NOREF(GCBaseAddr); NOREF(cbModule);
183 return VERR_NOT_IMPLEMENTED;
184#endif /* !VBOX_WITH_PAGE_SHARING */
185}
186
187#ifdef VBOX_WITH_PAGE_SHARING
188
189/**
190 * Rendezvous callback that will be called once.
191 *
192 * @returns VBox strict status code.
193 * @param pVM VM handle.
194 * @param pVCpu The VMCPU handle for the calling EMT.
195 * @param pvUser Not used;
196 */
197static DECLCALLBACK(VBOXSTRICTRC) pgmR3SharedModuleRegRendezvous(PVM pVM, PVMCPU pVCpu, void *pvUser)
198{
199 VMCPUID idCpu = *(VMCPUID *)pvUser;
200
201 /* Execute on the VCPU that issued the original request to make sure we're in the right cr3 context. */
202 if (pVCpu->idCpu != idCpu)
203 {
204 Assert(pVM->cCpus > 1);
205 return VINF_SUCCESS;
206 }
207
208 /* Flush all pending handy page operations before changing any shared page assignments. */
209 int rc = PGMR3PhysAllocateHandyPages(pVM);
210 AssertRC(rc);
211
212 /* Lock it here as we can't deal with busy locks in this ring-0 path. */
213 pgmLock(pVM);
214 rc = GMMR3CheckSharedModules(pVM);
215 pgmUnlock(pVM);
216 AssertLogRelRC(rc);
217 return rc;
218}
219
220/**
221 * Shared module check helper (called on the way out).
222 *
223 * @param pVM The VM handle.
224 * @param VMCPUID VCPU id
225 */
226static DECLCALLBACK(void) pgmR3CheckSharedModulesHelper(PVM pVM, VMCPUID idCpu)
227{
228 /* We must stall other VCPUs as we'd otherwise have to send IPI flush commands for every single change we make. */
229 int rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONE_BY_ONE, pgmR3SharedModuleRegRendezvous, &idCpu);
230 AssertRCSuccess(rc);
231}
232
233#endif /* !VBOX_WITH_PAGE_SHARING */
234
235/**
236 * Check all registered modules for changes.
237 *
238 * @returns VBox status code.
239 * @param pVM VM handle
240 */
241VMMR3DECL(int) PGMR3SharedModuleCheckAll(PVM pVM)
242{
243#ifdef VBOX_WITH_PAGE_SHARING
244 /* Queue the actual registration as we are under the IOM lock right now. Perform this operation on the way out. */
245 return VMR3ReqCallNoWait(pVM, VMCPUID_ANY_QUEUE, (PFNRT)pgmR3CheckSharedModulesHelper, 2, pVM, VMMGetCpuId(pVM));
246#else
247 NOREF(pVM);
248 return VERR_NOT_IMPLEMENTED;
249#endif
250}
251
252
253/**
254 * Query the state of a page in a shared module
255 *
256 * @returns VBox status code.
257 * @param pVM VM handle.
258 * @param GCPtrPage Page address.
259 * @param pfShared Shared status (out).
260 * @param pfPageFlags Page flags (out).
261 */
262VMMR3DECL(int) PGMR3SharedModuleGetPageState(PVM pVM, RTGCPTR GCPtrPage, bool *pfShared, uint64_t *pfPageFlags)
263{
264#if defined(VBOX_WITH_PAGE_SHARING) && defined(DEBUG)
265 /* Debug only API for the page fusion testcase. */
266 RTGCPHYS GCPhys;
267 uint64_t fFlags;
268
269 pgmLock(pVM);
270
271 int rc = PGMGstGetPage(VMMGetCpu(pVM), GCPtrPage, &fFlags, &GCPhys);
272 switch (rc)
273 {
274 case VINF_SUCCESS:
275 {
276 PPGMPAGE pPage = pgmPhysGetPage(pVM, GCPhys);
277 if (pPage)
278 {
279 *pfShared = PGM_PAGE_IS_SHARED(pPage);
280 *pfPageFlags = fFlags;
281 }
282 else
283 rc = VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS;
284 break;
285 }
286 case VERR_PAGE_NOT_PRESENT:
287 case VERR_PAGE_TABLE_NOT_PRESENT:
288 case VERR_PAGE_MAP_LEVEL4_NOT_PRESENT:
289 case VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT:
290 *pfShared = false;
291 *pfPageFlags = 0;
292 rc = VINF_SUCCESS;
293 break;
294
295 default:
296 break;
297 }
298
299 pgmUnlock(pVM);
300 return rc;
301#else
302 NOREF(pVM); NOREF(GCPtrPage); NOREF(pfShared); NOREF(pfPageFlags);
303 return VERR_NOT_IMPLEMENTED;
304#endif
305}
306
307#if defined(VBOX_WITH_PAGE_SHARING) && defined(VBOX_STRICT)
308
309/**
310 * The '.pgmcheckduppages' command.
311 *
312 * @returns VBox status.
313 * @param pCmd Pointer to the command descriptor (as registered).
314 * @param pCmdHlp Pointer to command helper functions.
315 * @param pVM Pointer to the current VM (if any).
316 * @param paArgs Pointer to (readonly) array of arguments.
317 * @param cArgs Number of arguments in the array.
318 */
319DECLCALLBACK(int) pgmR3CmdCheckDuplicatePages(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
320{
321 unsigned cBallooned = 0;
322 unsigned cShared = 0;
323 unsigned cZero = 0;
324 unsigned cUnique = 0;
325 unsigned cDuplicate = 0;
326 unsigned cAllocZero = 0;
327 unsigned cPages = 0;
328 NOREF(pCmd); NOREF(paArgs); NOREF(cArgs);
329
330 pgmLock(pVM);
331
332 for (PPGMRAMRANGE pRam = pVM->pgm.s.pRamRangesXR3; pRam; pRam = pRam->pNextR3)
333 {
334 PPGMPAGE pPage = &pRam->aPages[0];
335 RTGCPHYS GCPhys = pRam->GCPhys;
336 uint32_t cLeft = pRam->cb >> PAGE_SHIFT;
337 while (cLeft-- > 0)
338 {
339 if (PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_RAM)
340 {
341 switch (PGM_PAGE_GET_STATE(pPage))
342 {
343 case PGM_PAGE_STATE_ZERO:
344 cZero++;
345 break;
346
347 case PGM_PAGE_STATE_BALLOONED:
348 cBallooned++;
349 break;
350
351 case PGM_PAGE_STATE_SHARED:
352 cShared++;
353 break;
354
355 case PGM_PAGE_STATE_ALLOCATED:
356 case PGM_PAGE_STATE_WRITE_MONITORED:
357 {
358 /* Check if the page was allocated, but completely zero. */
359 PGMPAGEMAPLOCK PgMpLck;
360 const void *pvPage;
361 int rc = pgmPhysGCPhys2CCPtrInternalReadOnly(pVM, pPage, GCPhys, &pvPage, &PgMpLck);
362 if ( RT_SUCCESS(rc)
363 && ASMMemIsZeroPage(pvPage))
364 cAllocZero++;
365 else if (GMMR3IsDuplicatePage(pVM, PGM_PAGE_GET_PAGEID(pPage)))
366 cDuplicate++;
367 else
368 cUnique++;
369 if (RT_SUCCESS(rc))
370 pgmPhysReleaseInternalPageMappingLock(pVM, &PgMpLck);
371 break;
372 }
373
374 default:
375 AssertFailed();
376 break;
377 }
378 }
379
380 /* next */
381 pPage++;
382 GCPhys += PAGE_SIZE;
383 cPages++;
384 /* Give some feedback for every processed megabyte. */
385 if ((cPages & 0x7f) == 0)
386 pCmdHlp->pfnPrintf(pCmdHlp, NULL, ".");
387 }
388 }
389 pgmUnlock(pVM);
390
391 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\nNumber of zero pages %08x (%d MB)\n", cZero, cZero / 256);
392 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Number of alloczero pages %08x (%d MB)\n", cAllocZero, cAllocZero / 256);
393 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Number of ballooned pages %08x (%d MB)\n", cBallooned, cBallooned / 256);
394 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Number of shared pages %08x (%d MB)\n", cShared, cShared / 256);
395 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Number of unique pages %08x (%d MB)\n", cUnique, cUnique / 256);
396 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Number of duplicate pages %08x (%d MB)\n", cDuplicate, cDuplicate / 256);
397 return VINF_SUCCESS;
398}
399
400
401/**
402 * The '.pgmsharedmodules' command.
403 *
404 * @returns VBox status.
405 * @param pCmd Pointer to the command descriptor (as registered).
406 * @param pCmdHlp Pointer to command helper functions.
407 * @param pVM Pointer to the current VM (if any).
408 * @param paArgs Pointer to (readonly) array of arguments.
409 * @param cArgs Number of arguments in the array.
410 */
411DECLCALLBACK(int) pgmR3CmdShowSharedModules(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
412{
413 NOREF(pCmd); NOREF(paArgs); NOREF(cArgs);
414
415 pgmLock(pVM);
416 for (unsigned i = 0; i < RT_ELEMENTS(g_apSharedModules); i++)
417 {
418 if (g_apSharedModules[i])
419 {
420 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Shared module %s (%s):\n", g_apSharedModules[i]->szName, g_apSharedModules[i]->szVersion);
421 for (unsigned j = 0; j < g_apSharedModules[i]->cRegions; j++)
422 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "--- Region %d: base %RGv size %x\n", j, g_apSharedModules[i]->aRegions[j].GCRegionAddr, g_apSharedModules[i]->aRegions[j].cbRegion);
423 }
424 }
425 pgmUnlock(pVM);
426
427 return VINF_SUCCESS;
428}
429
430#endif /* VBOX_STRICT && VBOX_WITH_PAGE_SHARING */
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