VirtualBox

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

Last change on this file since 32048 was 31529, checked in by vboxsync, 14 years ago

pSharedModules -> g_apSharedModules. (r64559 looked like RT_ELEMENTS was applied to a pointer.)

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