~ubuntu-branches/ubuntu/trusty/virtualbox-lts-xenial/trusty-proposed

« back to all changes in this revision

Viewing changes to src/VBox/Additions/common/VBoxService/VBoxServicePageSharing.cpp

  • Committer: Package Import Robot
  • Author(s): Gianfranco Costamagna
  • Date: 2016-02-23 14:28:26 UTC
  • Revision ID: package-import@ubuntu.com-20160223142826-bdu69el2z6wa2a44
Tags: upstream-4.3.36-dfsg
ImportĀ upstreamĀ versionĀ 4.3.36-dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: VBoxServicePageSharing.cpp $ */
 
2
/** @file
 
3
 * VBoxService - Guest page sharing.
 
4
 */
 
5
 
 
6
/*
 
7
 * Copyright (C) 2006-2012 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
#include <iprt/assert.h>
 
23
#include <iprt/avl.h>
 
24
#include <iprt/asm.h>
 
25
#include <iprt/mem.h>
 
26
#include <iprt/ldr.h>
 
27
#include <iprt/process.h>
 
28
#include <iprt/env.h>
 
29
#include <iprt/stream.h>
 
30
#include <iprt/file.h>
 
31
#include <iprt/string.h>
 
32
#include <iprt/semaphore.h>
 
33
#include <iprt/system.h>
 
34
#include <iprt/thread.h>
 
35
#include <iprt/time.h>
 
36
#include <VBox/VBoxGuestLib.h>
 
37
#include "VBoxServiceInternal.h"
 
38
#include "VBoxServiceUtils.h"
 
39
 
 
40
 
 
41
/*******************************************************************************
 
42
*   Global Variables                                                           *
 
43
*******************************************************************************/
 
44
 
 
45
/** The semaphore we're blocking on. */
 
46
static RTSEMEVENTMULTI  g_PageSharingEvent = NIL_RTSEMEVENTMULTI;
 
47
 
 
48
#if defined(RT_OS_WINDOWS) && !defined(TARGET_NT4)
 
49
#include <tlhelp32.h>
 
50
#include <psapi.h>
 
51
#include <winternl.h>
 
52
 
 
53
typedef struct
 
54
{
 
55
    AVLPVNODECORE   Core;
 
56
    HMODULE         hModule;
 
57
    char            szFileVersion[16];
 
58
    MODULEENTRY32   Info;
 
59
} KNOWN_MODULE, *PKNOWN_MODULE;
 
60
 
 
61
#define SystemModuleInformation     11
 
62
 
 
63
typedef struct _RTL_PROCESS_MODULE_INFORMATION
 
64
{
 
65
    ULONG Section;
 
66
    PVOID MappedBase;
 
67
    PVOID ImageBase;
 
68
    ULONG ImageSize;
 
69
    ULONG Flags;
 
70
    USHORT LoadOrderIndex;
 
71
    USHORT InitOrderIndex;
 
72
    USHORT LoadCount;
 
73
    USHORT OffsetToFileName;
 
74
    CHAR FullPathName[256];
 
75
} RTL_PROCESS_MODULE_INFORMATION, *PRTL_PROCESS_MODULE_INFORMATION;
 
76
 
 
77
typedef struct _RTL_PROCESS_MODULES
 
78
{
 
79
    ULONG NumberOfModules;
 
80
    RTL_PROCESS_MODULE_INFORMATION Modules[1];
 
81
} RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES;
 
82
 
 
83
typedef NTSTATUS (WINAPI *PFNZWQUERYSYSTEMINFORMATION)(ULONG, PVOID, ULONG, PULONG);
 
84
static PFNZWQUERYSYSTEMINFORMATION g_pfnZwQuerySystemInformation = NULL;
 
85
 
 
86
 
 
87
static DECLCALLBACK(int) VBoxServicePageSharingEmptyTreeCallback(PAVLPVNODECORE pNode, void *pvUser);
 
88
 
 
89
static PAVLPVNODECORE   g_pKnownModuleTree = NULL;
 
90
static uint64_t         g_idSession = 0;
 
91
 
 
92
/**
 
93
 * Registers a new module with the VMM
 
94
 * @param   pModule         Module ptr
 
95
 * @param   fValidateMemory Validate/touch memory pages or not
 
96
 */
 
97
void VBoxServicePageSharingRegisterModule(PKNOWN_MODULE pModule, bool fValidateMemory)
 
98
{
 
99
    VMMDEVSHAREDREGIONDESC   aRegions[VMMDEVSHAREDREGIONDESC_MAX];
 
100
    DWORD                    dwModuleSize = pModule->Info.modBaseSize;
 
101
    BYTE                    *pBaseAddress = pModule->Info.modBaseAddr;
 
102
    DWORD                    cbVersionSize, dummy;
 
103
    BYTE                    *pVersionInfo;
 
104
 
 
105
    VBoxServiceVerbose(3, "VBoxServicePageSharingRegisterModule\n");
 
106
 
 
107
    cbVersionSize = GetFileVersionInfoSize(pModule->Info.szExePath, &dummy);
 
108
    if (!cbVersionSize)
 
109
    {
 
110
        VBoxServiceVerbose(3, "VBoxServicePageSharingRegisterModule: GetFileVersionInfoSize failed with %d\n", GetLastError());
 
111
        return;
 
112
    }
 
113
    pVersionInfo = (BYTE *)RTMemAlloc(cbVersionSize);
 
114
    if (!pVersionInfo)
 
115
        return;
 
116
 
 
117
    if (!GetFileVersionInfo(pModule->Info.szExePath, 0, cbVersionSize, pVersionInfo))
 
118
    {
 
119
        VBoxServiceVerbose(3, "VBoxServicePageSharingRegisterModule: GetFileVersionInfo failed with %d\n", GetLastError());
 
120
        goto end;
 
121
    }
 
122
 
 
123
    /* Fetch default code page. */
 
124
    struct LANGANDCODEPAGE {
 
125
        WORD wLanguage;
 
126
        WORD wCodePage;
 
127
    } *lpTranslate;
 
128
 
 
129
    UINT   cbTranslate;
 
130
    BOOL ret = VerQueryValue(pVersionInfo, TEXT("\\VarFileInfo\\Translation"), (LPVOID *)&lpTranslate, &cbTranslate);
 
131
    if (    !ret
 
132
        ||  cbTranslate < 4)
 
133
    {
 
134
        VBoxServiceVerbose(3, "VBoxServicePageSharingRegisterModule: VerQueryValue failed with %d (cb=%d)\n", GetLastError(), cbTranslate);
 
135
        goto end;
 
136
    }
 
137
 
 
138
    unsigned i;
 
139
    UINT     cbFileVersion;
 
140
    char    *lpszFileVersion;
 
141
    unsigned cTranslationBlocks = cbTranslate/sizeof(struct LANGANDCODEPAGE);
 
142
 
 
143
    for(i = 0; i < cTranslationBlocks; i++)
 
144
    {
 
145
        /* Fetch file version string. */
 
146
        char   szFileVersionLocation[256];
 
147
 
 
148
        sprintf(szFileVersionLocation, TEXT("\\StringFileInfo\\%04x%04x\\FileVersion"), lpTranslate[i].wLanguage, lpTranslate[i].wCodePage);
 
149
        ret = VerQueryValue(pVersionInfo, szFileVersionLocation, (LPVOID *)&lpszFileVersion, &cbFileVersion);
 
150
        if (ret)
 
151
            break;
 
152
    }
 
153
    if (i == cTranslationBlocks)
 
154
    {
 
155
        VBoxServiceVerbose(3, "VBoxServicePageSharingRegisterModule: no file version found!\n");
 
156
        goto end;
 
157
    }
 
158
 
 
159
    _snprintf(pModule->szFileVersion, sizeof(pModule->szFileVersion), "%s", lpszFileVersion);
 
160
    pModule->szFileVersion[RT_ELEMENTS(pModule->szFileVersion) - 1] = 0;
 
161
 
 
162
    unsigned idxRegion = 0;
 
163
 
 
164
    if (fValidateMemory)
 
165
    {
 
166
        do
 
167
        {
 
168
            MEMORY_BASIC_INFORMATION MemInfo;
 
169
 
 
170
            SIZE_T ret = VirtualQuery(pBaseAddress, &MemInfo, sizeof(MemInfo));
 
171
            Assert(ret);
 
172
            if (!ret)
 
173
            {
 
174
                VBoxServiceVerbose(3, "VBoxServicePageSharingRegisterModule: VirtualQueryEx failed with %d\n", GetLastError());
 
175
                break;
 
176
            }
 
177
 
 
178
            if (    MemInfo.State == MEM_COMMIT
 
179
                &&  MemInfo.Type == MEM_IMAGE)
 
180
            {
 
181
                switch (MemInfo.Protect)
 
182
                {
 
183
                case PAGE_EXECUTE:
 
184
                case PAGE_EXECUTE_READ:
 
185
                case PAGE_READONLY:
 
186
                {
 
187
                    char *pRegion = (char *)MemInfo.BaseAddress;
 
188
 
 
189
                    /* Skip the first region as it only contains the image file header. */
 
190
                    if (pRegion != (char *)pModule->Info.modBaseAddr)
 
191
                    {
 
192
                        /* Touch all pages. */
 
193
                        while (pRegion < (char *)MemInfo.BaseAddress + MemInfo.RegionSize)
 
194
                        {
 
195
                            /* Try to trick the optimizer to leave the page touching code in place. */
 
196
                            ASMProbeReadByte(pRegion);
 
197
                            pRegion += PAGE_SIZE;
 
198
                        }
 
199
                    }
 
200
#ifdef RT_ARCH_X86
 
201
                    aRegions[idxRegion].GCRegionAddr = (RTGCPTR32)MemInfo.BaseAddress;
 
202
#else
 
203
                    aRegions[idxRegion].GCRegionAddr = (RTGCPTR64)MemInfo.BaseAddress;
 
204
#endif
 
205
                    aRegions[idxRegion].cbRegion     = MemInfo.RegionSize;
 
206
                    idxRegion++;
 
207
 
 
208
                    break;
 
209
                }
 
210
 
 
211
                default:
 
212
                    break; /* ignore */
 
213
                }
 
214
            }
 
215
 
 
216
            pBaseAddress = (BYTE *)MemInfo.BaseAddress + MemInfo.RegionSize;
 
217
            if (dwModuleSize > MemInfo.RegionSize)
 
218
            {
 
219
                dwModuleSize -= MemInfo.RegionSize;
 
220
            }
 
221
            else
 
222
            {
 
223
                dwModuleSize = 0;
 
224
                break;
 
225
            }
 
226
 
 
227
            if (idxRegion >= RT_ELEMENTS(aRegions))
 
228
                break;  /* out of room */
 
229
        }
 
230
        while (dwModuleSize);
 
231
    }
 
232
    else
 
233
    {
 
234
        /* We can't probe kernel memory ranges, so pretend it's one big region. */
 
235
#ifdef RT_ARCH_X86
 
236
        aRegions[idxRegion].GCRegionAddr = (RTGCPTR32)pBaseAddress;
 
237
#else
 
238
        aRegions[idxRegion].GCRegionAddr = (RTGCPTR64)pBaseAddress;
 
239
#endif
 
240
        aRegions[idxRegion].cbRegion     = dwModuleSize;
 
241
        idxRegion++;
 
242
    }
 
243
    VBoxServiceVerbose(3, "VBoxServicePageSharingRegisterModule: VbglR3RegisterSharedModule %s %s base=%p size=%x cregions=%d\n", pModule->Info.szModule, pModule->szFileVersion, pModule->Info.modBaseAddr, pModule->Info.modBaseSize, idxRegion);
 
244
    int rc = VbglR3RegisterSharedModule(pModule->Info.szModule, pModule->szFileVersion, (uintptr_t)pModule->Info.modBaseAddr,
 
245
                                        pModule->Info.modBaseSize, idxRegion, aRegions);
 
246
    if (RT_FAILURE(rc))
 
247
        VBoxServiceVerbose(3, "VBoxServicePageSharingRegisterModule: VbglR3RegisterSharedModule failed with %Rrc\n", rc);
 
248
 
 
249
end:
 
250
    RTMemFree(pVersionInfo);
 
251
    return;
 
252
}
 
253
 
 
254
/**
 
255
 * Inspect all loaded modules for the specified process
 
256
 * @param   dwProcessId     Process id
 
257
 */
 
258
void VBoxServicePageSharingInspectModules(DWORD dwProcessId, PAVLPVNODECORE *ppNewTree)
 
259
{
 
260
    HANDLE hProcess, hSnapshot;
 
261
 
 
262
    /* Get a list of all the modules in this process. */
 
263
    hProcess = OpenProcess(PROCESS_QUERY_INFORMATION,
 
264
                           FALSE /* no child process handle inheritance */, dwProcessId);
 
265
    if (hProcess == NULL)
 
266
    {
 
267
        VBoxServiceVerbose(3, "VBoxServicePageSharingInspectModules: OpenProcess %x failed with %d\n", dwProcessId, GetLastError());
 
268
        return;
 
269
    }
 
270
 
 
271
    hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId);
 
272
    if (hSnapshot == INVALID_HANDLE_VALUE)
 
273
    {
 
274
        VBoxServiceVerbose(3, "VBoxServicePageSharingInspectModules: CreateToolhelp32Snapshot failed with %d\n", GetLastError());
 
275
        CloseHandle(hProcess);
 
276
        return;
 
277
    }
 
278
 
 
279
    VBoxServiceVerbose(3, "VBoxServicePageSharingInspectModules\n");
 
280
 
 
281
    MODULEENTRY32 ModuleInfo;
 
282
    BOOL          bRet;
 
283
 
 
284
    ModuleInfo.dwSize = sizeof(ModuleInfo);
 
285
    bRet = Module32First(hSnapshot, &ModuleInfo);
 
286
    do
 
287
    {
 
288
        /** @todo when changing this make sure VBoxService.exe is excluded! */
 
289
        char *pszDot = strrchr(ModuleInfo.szModule, '.');
 
290
        if (    pszDot
 
291
            &&  (pszDot[1] == 'e' || pszDot[1] == 'E'))
 
292
            continue;   /* ignore executables for now. */
 
293
 
 
294
        /* Found it before? */
 
295
        PAVLPVNODECORE pRec = RTAvlPVGet(ppNewTree, ModuleInfo.modBaseAddr);
 
296
        if (!pRec)
 
297
        {
 
298
            pRec = RTAvlPVRemove(&g_pKnownModuleTree, ModuleInfo.modBaseAddr);
 
299
            if (!pRec)
 
300
            {
 
301
                /* New module; register it. */
 
302
                PKNOWN_MODULE pModule = (PKNOWN_MODULE)RTMemAllocZ(sizeof(*pModule));
 
303
                Assert(pModule);
 
304
                if (!pModule)
 
305
                    break;
 
306
 
 
307
                pModule->Info     = ModuleInfo;
 
308
                pModule->Core.Key = ModuleInfo.modBaseAddr;
 
309
                pModule->hModule  = LoadLibraryEx(ModuleInfo.szExePath, 0, DONT_RESOLVE_DLL_REFERENCES);
 
310
                if (pModule->hModule)
 
311
                    VBoxServicePageSharingRegisterModule(pModule, true /* validate pages */);
 
312
 
 
313
                VBoxServiceVerbose(3, "\n\n     MODULE NAME:     %s",           ModuleInfo.szModule );
 
314
                VBoxServiceVerbose(3, "\n     executable     = %s",             ModuleInfo.szExePath );
 
315
                VBoxServiceVerbose(3, "\n     process ID     = 0x%08X",         ModuleInfo.th32ProcessID );
 
316
                VBoxServiceVerbose(3, "\n     base address   = 0x%08X", (DWORD) ModuleInfo.modBaseAddr );
 
317
                VBoxServiceVerbose(3, "\n     base size      = %d",             ModuleInfo.modBaseSize );
 
318
 
 
319
                pRec = &pModule->Core;
 
320
            }
 
321
            bool ret = RTAvlPVInsert(ppNewTree, pRec);
 
322
            Assert(ret); NOREF(ret);
 
323
        }
 
324
    }
 
325
    while (Module32Next(hSnapshot, &ModuleInfo));
 
326
 
 
327
    CloseHandle(hSnapshot);
 
328
    CloseHandle(hProcess);
 
329
}
 
330
 
 
331
/**
 
332
 * Inspect all running processes for executables and dlls that might be worth sharing
 
333
 * with other VMs.
 
334
 *
 
335
 */
 
336
void VBoxServicePageSharingInspectGuest()
 
337
{
 
338
    HANDLE hSnapshot;
 
339
    PAVLPVNODECORE pNewTree = NULL;
 
340
    DWORD dwProcessId = GetCurrentProcessId();
 
341
 
 
342
    VBoxServiceVerbose(3, "VBoxServicePageSharingInspectGuest\n");
 
343
 
 
344
    hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
 
345
    if (hSnapshot == INVALID_HANDLE_VALUE)
 
346
    {
 
347
        VBoxServiceVerbose(3, "VBoxServicePageSharingInspectGuest: CreateToolhelp32Snapshot failed with %d\n", GetLastError());
 
348
        return;
 
349
    }
 
350
 
 
351
    /* Check loaded modules for all running processes. */
 
352
    PROCESSENTRY32 ProcessInfo;
 
353
 
 
354
    ProcessInfo.dwSize = sizeof(ProcessInfo);
 
355
    Process32First(hSnapshot, &ProcessInfo);
 
356
 
 
357
    do
 
358
    {
 
359
        /* Skip our own process. */
 
360
        if (ProcessInfo.th32ProcessID != dwProcessId)
 
361
            VBoxServicePageSharingInspectModules(ProcessInfo.th32ProcessID, &pNewTree);
 
362
    }
 
363
    while (Process32Next(hSnapshot, &ProcessInfo));
 
364
 
 
365
    CloseHandle(hSnapshot);
 
366
 
 
367
    /* Check all loaded kernel modules. */
 
368
    if (g_pfnZwQuerySystemInformation)
 
369
    {
 
370
        ULONG                cbBuffer = 0;
 
371
        PVOID                pBuffer = NULL;
 
372
        PRTL_PROCESS_MODULES pSystemModules;
 
373
 
 
374
        NTSTATUS ret = g_pfnZwQuerySystemInformation(SystemModuleInformation, (PVOID)&cbBuffer, 0, &cbBuffer);
 
375
        if (!cbBuffer)
 
376
        {
 
377
            VBoxServiceVerbose(1, "ZwQuerySystemInformation returned length 0\n");
 
378
            goto skipkernelmodules;
 
379
        }
 
380
 
 
381
        pBuffer = RTMemAllocZ(cbBuffer);
 
382
        if (!pBuffer)
 
383
            goto skipkernelmodules;
 
384
 
 
385
        ret = g_pfnZwQuerySystemInformation(SystemModuleInformation, pBuffer, cbBuffer, &cbBuffer);
 
386
        if (ret != STATUS_SUCCESS)
 
387
        {
 
388
            VBoxServiceVerbose(1, "ZwQuerySystemInformation returned %x (1)\n", ret);
 
389
            goto skipkernelmodules;
 
390
        }
 
391
 
 
392
        pSystemModules = (PRTL_PROCESS_MODULES)pBuffer;
 
393
        for (unsigned i = 0; i < pSystemModules->NumberOfModules; i++)
 
394
        {
 
395
            VBoxServiceVerbose(4, "\n\n   KERNEL  MODULE NAME:     %s",     pSystemModules->Modules[i].FullPathName[pSystemModules->Modules[i].OffsetToFileName] );
 
396
            VBoxServiceVerbose(4, "\n     executable     = %s",             pSystemModules->Modules[i].FullPathName );
 
397
            VBoxServiceVerbose(4, "\n     flags          = 0x%08X\n",       pSystemModules->Modules[i].Flags);
 
398
 
 
399
            /* User-mode modules seem to have no flags set; skip them as we detected them above. */
 
400
            if (pSystemModules->Modules[i].Flags == 0)
 
401
                continue;
 
402
 
 
403
            /* Found it before? */
 
404
            PAVLPVNODECORE pRec = RTAvlPVGet(&pNewTree, pSystemModules->Modules[i].ImageBase);
 
405
            if (!pRec)
 
406
            {
 
407
                pRec = RTAvlPVRemove(&g_pKnownModuleTree, pSystemModules->Modules[i].ImageBase);
 
408
                if (!pRec)
 
409
                {
 
410
                    /* New module; register it. */
 
411
                    char          szFullFilePath[512];
 
412
                    PKNOWN_MODULE pModule = (PKNOWN_MODULE)RTMemAllocZ(sizeof(*pModule));
 
413
                    Assert(pModule);
 
414
                    if (!pModule)
 
415
                        break;
 
416
 
 
417
                    strcpy(pModule->Info.szModule, &pSystemModules->Modules[i].FullPathName[pSystemModules->Modules[i].OffsetToFileName]);
 
418
                    GetSystemDirectoryA(szFullFilePath, sizeof(szFullFilePath));
 
419
 
 
420
                    /* skip \Systemroot\system32 */
 
421
                    char *lpPath = strchr(&pSystemModules->Modules[i].FullPathName[1], '\\');
 
422
                    if (!lpPath)
 
423
                    {
 
424
                        /* Seen just file names in XP; try to locate the file in the system32 and system32\drivers directories. */
 
425
                        strcat(szFullFilePath, "\\");
 
426
                        strcat(szFullFilePath, pSystemModules->Modules[i].FullPathName);
 
427
                        VBoxServiceVerbose(3, "Unexpected kernel module name try %s\n", szFullFilePath);
 
428
                        if (RTFileExists(szFullFilePath) == false)
 
429
                        {
 
430
                            GetSystemDirectoryA(szFullFilePath, sizeof(szFullFilePath));
 
431
                            strcat(szFullFilePath, "\\drivers\\");
 
432
                            strcat(szFullFilePath, pSystemModules->Modules[i].FullPathName);
 
433
                            VBoxServiceVerbose(3, "Unexpected kernel module name try %s\n", szFullFilePath);
 
434
                            if (RTFileExists(szFullFilePath) == false)
 
435
                            {
 
436
                                VBoxServiceVerbose(1, "Unexpected kernel module name %s\n", pSystemModules->Modules[i].FullPathName);
 
437
                                RTMemFree(pModule);
 
438
                                continue;
 
439
                            }
 
440
                        }
 
441
                    }
 
442
                    else
 
443
                    {
 
444
                        lpPath = strchr(lpPath+1, '\\');
 
445
                        if (!lpPath)
 
446
                        {
 
447
                            VBoxServiceVerbose(1, "Unexpected kernel module name %s (2)\n", pSystemModules->Modules[i].FullPathName);
 
448
                            RTMemFree(pModule);
 
449
                            continue;
 
450
                        }
 
451
 
 
452
                        strcat(szFullFilePath, lpPath);
 
453
                    }
 
454
 
 
455
                    strcpy(pModule->Info.szExePath, szFullFilePath);
 
456
                    pModule->Info.modBaseAddr = (BYTE *)pSystemModules->Modules[i].ImageBase;
 
457
                    pModule->Info.modBaseSize = pSystemModules->Modules[i].ImageSize;
 
458
 
 
459
                    pModule->Core.Key = pSystemModules->Modules[i].ImageBase;
 
460
                    VBoxServicePageSharingRegisterModule(pModule, false /* don't check memory pages */);
 
461
 
 
462
                    VBoxServiceVerbose(3, "\n\n   KERNEL  MODULE NAME:     %s",     pModule->Info.szModule );
 
463
                    VBoxServiceVerbose(3, "\n     executable     = %s",             pModule->Info.szExePath );
 
464
                    VBoxServiceVerbose(3, "\n     base address   = 0x%08X", (DWORD) pModule->Info.modBaseAddr );
 
465
                    VBoxServiceVerbose(3, "\n     flags          = 0x%08X",         pSystemModules->Modules[i].Flags);
 
466
                    VBoxServiceVerbose(3, "\n     base size      = %d",             pModule->Info.modBaseSize );
 
467
 
 
468
                    pRec = &pModule->Core;
 
469
                }
 
470
                bool ret = RTAvlPVInsert(&pNewTree, pRec);
 
471
                Assert(ret); NOREF(ret);
 
472
            }
 
473
        }
 
474
skipkernelmodules:
 
475
        if (pBuffer)
 
476
            RTMemFree(pBuffer);
 
477
    }
 
478
 
 
479
    /* Delete leftover modules in the old tree. */
 
480
    RTAvlPVDestroy(&g_pKnownModuleTree, VBoxServicePageSharingEmptyTreeCallback, NULL);
 
481
 
 
482
    /* Check all registered modules. */
 
483
    VbglR3CheckSharedModules();
 
484
 
 
485
    /* Activate new module tree. */
 
486
    g_pKnownModuleTree = pNewTree;
 
487
}
 
488
 
 
489
/**
 
490
 * RTAvlPVDestroy callback.
 
491
 */
 
492
static DECLCALLBACK(int) VBoxServicePageSharingEmptyTreeCallback(PAVLPVNODECORE pNode, void *pvUser)
 
493
{
 
494
    PKNOWN_MODULE pModule = (PKNOWN_MODULE)pNode;
 
495
    bool *pfUnregister = (bool *)pvUser;
 
496
 
 
497
    VBoxServiceVerbose(3, "VBoxServicePageSharingEmptyTreeCallback %s %s\n", pModule->Info.szModule, pModule->szFileVersion);
 
498
 
 
499
    /* Dereference module in the hypervisor. */
 
500
    if (   !pfUnregister
 
501
        || *pfUnregister)
 
502
    {
 
503
        int rc = VbglR3UnregisterSharedModule(pModule->Info.szModule, pModule->szFileVersion,
 
504
                                              (uintptr_t)pModule->Info.modBaseAddr, pModule->Info.modBaseSize);
 
505
        AssertRC(rc);
 
506
    }
 
507
 
 
508
    if (pModule->hModule)
 
509
        FreeLibrary(pModule->hModule);
 
510
    RTMemFree(pNode);
 
511
    return 0;
 
512
}
 
513
 
 
514
 
 
515
#elif TARGET_NT4
 
516
void VBoxServicePageSharingInspectGuest()
 
517
{
 
518
    /* not implemented */
 
519
}
 
520
#else
 
521
void VBoxServicePageSharingInspectGuest()
 
522
{
 
523
    /* @todo other platforms */
 
524
}
 
525
#endif
 
526
 
 
527
/** @copydoc VBOXSERVICE::pfnInit */
 
528
static DECLCALLBACK(int) VBoxServicePageSharingInit(void)
 
529
{
 
530
    VBoxServiceVerbose(3, "VBoxServicePageSharingInit\n");
 
531
 
 
532
    int rc = RTSemEventMultiCreate(&g_PageSharingEvent);
 
533
    AssertRCReturn(rc, rc);
 
534
 
 
535
#if defined(RT_OS_WINDOWS) && !defined(TARGET_NT4)
 
536
    g_pfnZwQuerySystemInformation = (PFNZWQUERYSYSTEMINFORMATION)RTLdrGetSystemSymbol("ntdll.dll", "ZwQuerySystemInformation");
 
537
 
 
538
    rc = VbglR3GetSessionId(&g_idSession);
 
539
    if (RT_FAILURE(rc))
 
540
    {
 
541
        if (rc == VERR_IO_GEN_FAILURE)
 
542
            VBoxServiceVerbose(0, "PageSharing: Page sharing support is not available by the host\n");
 
543
        else
 
544
            VBoxServiceError("VBoxServicePageSharingInit: Failed with rc=%Rrc\n", rc);
 
545
 
 
546
        rc = VERR_SERVICE_DISABLED;
 
547
 
 
548
        RTSemEventMultiDestroy(g_PageSharingEvent);
 
549
        g_PageSharingEvent = NIL_RTSEMEVENTMULTI;
 
550
 
 
551
    }
 
552
#endif
 
553
 
 
554
    return rc;
 
555
}
 
556
 
 
557
/** @copydoc VBOXSERVICE::pfnWorker */
 
558
DECLCALLBACK(int) VBoxServicePageSharingWorker(bool volatile *pfShutdown)
 
559
{
 
560
    /*
 
561
     * Tell the control thread that it can continue
 
562
     * spawning services.
 
563
     */
 
564
    RTThreadUserSignal(RTThreadSelf());
 
565
 
 
566
    /*
 
567
     * Now enter the loop retrieving runtime data continuously.
 
568
     */
 
569
    for (;;)
 
570
    {
 
571
        BOOL fEnabled = VbglR3PageSharingIsEnabled();
 
572
 
 
573
        VBoxServiceVerbose(3, "VBoxServicePageSharingWorker: enabled=%d\n", fEnabled);
 
574
 
 
575
        if (fEnabled)
 
576
            VBoxServicePageSharingInspectGuest();
 
577
 
 
578
        /*
 
579
         * Block for a minute.
 
580
         *
 
581
         * The event semaphore takes care of ignoring interruptions and it
 
582
         * allows us to implement service wakeup later.
 
583
         */
 
584
        if (*pfShutdown)
 
585
            break;
 
586
        int rc = RTSemEventMultiWait(g_PageSharingEvent, 60000);
 
587
        if (*pfShutdown)
 
588
            break;
 
589
        if (rc != VERR_TIMEOUT && RT_FAILURE(rc))
 
590
        {
 
591
            VBoxServiceError("VBoxServicePageSharingWorker: RTSemEventMultiWait failed; rc=%Rrc\n", rc);
 
592
            break;
 
593
        }
 
594
#if defined(RT_OS_WINDOWS) && !defined(TARGET_NT4)
 
595
        uint64_t idNewSession = g_idSession;
 
596
        rc =  VbglR3GetSessionId(&idNewSession);
 
597
        AssertRC(rc);
 
598
 
 
599
        if (idNewSession != g_idSession)
 
600
        {
 
601
            bool fUnregister = false;
 
602
 
 
603
            VBoxServiceVerbose(3, "VBoxServicePageSharingWorker: VM was restored!!\n");
 
604
            /* The VM was restored, so reregister all modules the next time. */
 
605
            RTAvlPVDestroy(&g_pKnownModuleTree, VBoxServicePageSharingEmptyTreeCallback, &fUnregister);
 
606
            g_pKnownModuleTree = NULL;
 
607
 
 
608
            g_idSession = idNewSession;
 
609
        }
 
610
#endif
 
611
    }
 
612
 
 
613
    RTSemEventMultiDestroy(g_PageSharingEvent);
 
614
    g_PageSharingEvent = NIL_RTSEMEVENTMULTI;
 
615
 
 
616
    VBoxServiceVerbose(3, "VBoxServicePageSharingWorker: finished thread\n");
 
617
    return 0;
 
618
}
 
619
 
 
620
#ifdef RT_OS_WINDOWS
 
621
 
 
622
/**
 
623
 * This gets control when VBoxService is launched with -pagefusionfork by
 
624
 * VBoxServicePageSharingWorkerProcess().
 
625
 *
 
626
 * @returns RTEXITCODE_SUCCESS.
 
627
 *
 
628
 * @remarks It won't normally return since the parent drops the shutdown hint
 
629
 *          via RTProcTerminate().
 
630
 */
 
631
RTEXITCODE VBoxServicePageSharingInitFork(void)
 
632
{
 
633
    VBoxServiceVerbose(3, "VBoxServicePageSharingInitFork\n");
 
634
 
 
635
    bool fShutdown = false;
 
636
    VBoxServicePageSharingInit();
 
637
    VBoxServicePageSharingWorker(&fShutdown);
 
638
 
 
639
    return RTEXITCODE_SUCCESS;
 
640
}
 
641
 
 
642
/** @copydoc VBOXSERVICE::pfnWorker */
 
643
DECLCALLBACK(int) VBoxServicePageSharingWorkerProcess(bool volatile *pfShutdown)
 
644
{
 
645
    RTPROCESS hProcess = NIL_RTPROCESS;
 
646
    int rc;
 
647
 
 
648
    /*
 
649
     * Tell the control thread that it can continue
 
650
     * spawning services.
 
651
     */
 
652
    RTThreadUserSignal(RTThreadSelf());
 
653
 
 
654
    /*
 
655
     * Now enter the loop retrieving runtime data continuously.
 
656
     */
 
657
    for (;;)
 
658
    {
 
659
        BOOL fEnabled = VbglR3PageSharingIsEnabled();
 
660
        VBoxServiceVerbose(3, "VBoxServicePageSharingWorkerProcess: enabled=%d\n", fEnabled);
 
661
 
 
662
        /*
 
663
         * Start a 2nd VBoxService process to deal with page fusion as we do
 
664
         * not wish to dummy load dlls into this process.  (First load with
 
665
         * DONT_RESOLVE_DLL_REFERENCES, 2nd normal -> dll init routines not called!)
 
666
         */
 
667
        if (    fEnabled
 
668
            &&  hProcess == NIL_RTPROCESS)
 
669
        {
 
670
            char szExeName[256];
 
671
            char *pszExeName = RTProcGetExecutablePath(szExeName, sizeof(szExeName));
 
672
            if (pszExeName)
 
673
            {
 
674
                char const *papszArgs[3];
 
675
                papszArgs[0] = pszExeName;
 
676
                papszArgs[1] = "pagefusion";
 
677
                papszArgs[2] = NULL;
 
678
                rc = RTProcCreate(pszExeName, papszArgs, RTENV_DEFAULT, 0 /* normal child */, &hProcess);
 
679
                if (RT_FAILURE(rc))
 
680
                    VBoxServiceError("VBoxServicePageSharingWorkerProcess: RTProcCreate %s failed; rc=%Rrc\n", pszExeName, rc);
 
681
            }
 
682
        }
 
683
 
 
684
        /*
 
685
         * Block for a minute.
 
686
         *
 
687
         * The event semaphore takes care of ignoring interruptions and it
 
688
         * allows us to implement service wakeup later.
 
689
         */
 
690
        if (*pfShutdown)
 
691
            break;
 
692
        rc = RTSemEventMultiWait(g_PageSharingEvent, 60000);
 
693
        if (*pfShutdown)
 
694
            break;
 
695
        if (rc != VERR_TIMEOUT && RT_FAILURE(rc))
 
696
        {
 
697
            VBoxServiceError("VBoxServicePageSharingWorkerProcess: RTSemEventMultiWait failed; rc=%Rrc\n", rc);
 
698
            break;
 
699
        }
 
700
    }
 
701
 
 
702
    if (hProcess != NIL_RTPROCESS)
 
703
        RTProcTerminate(hProcess);
 
704
 
 
705
    RTSemEventMultiDestroy(g_PageSharingEvent);
 
706
    g_PageSharingEvent = NIL_RTSEMEVENTMULTI;
 
707
 
 
708
    VBoxServiceVerbose(3, "VBoxServicePageSharingWorkerProcess: finished thread\n");
 
709
    return 0;
 
710
}
 
711
 
 
712
#endif /* RT_OS_WINDOWS */
 
713
 
 
714
/** @copydoc VBOXSERVICE::pfnStop */
 
715
static DECLCALLBACK(void) VBoxServicePageSharingStop(void)
 
716
{
 
717
    RTSemEventMultiSignal(g_PageSharingEvent);
 
718
}
 
719
 
 
720
 
 
721
/**
 
722
 * The 'pagesharing' service description.
 
723
 */
 
724
VBOXSERVICE g_PageSharing =
 
725
{
 
726
    /* pszName. */
 
727
    "pagesharing",
 
728
    /* pszDescription. */
 
729
    "Page Sharing",
 
730
    /* pszUsage. */
 
731
    NULL,
 
732
    /* pszOptions. */
 
733
    NULL,
 
734
    /* methods */
 
735
    VBoxServiceDefaultPreInit,
 
736
    VBoxServiceDefaultOption,
 
737
    VBoxServicePageSharingInit,
 
738
#ifdef RT_OS_WINDOWS
 
739
    VBoxServicePageSharingWorkerProcess,
 
740
#else
 
741
    VBoxServicePageSharingWorker,
 
742
#endif
 
743
    VBoxServicePageSharingStop,
 
744
    VBoxServiceDefaultTerm
 
745
};