VirtualBox

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

Last change on this file since 30934 was 30887, checked in by vboxsync, 14 years ago

PGMSharedPage.cpp: PGMInline.h must come after all other includes.

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