VirtualBox

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

Last change on this file since 31463 was 31365, checked in by vboxsync, 14 years ago

Update

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