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

« back to all changes in this revision

Viewing changes to .pc/27-hide-host-cache-warning.patch/src/VBox/Main/src-client/ConsoleImpl2.cpp

  • Committer: Package Import Robot
  • Author(s): Gianfranco Costamagna
  • Date: 2016-02-23 14:28:26 UTC
  • Revision ID: package-import@ubuntu.com-20160223142826-kpprg3lfwn2izud0
Tags: 4.3.36-dfsg-1+deb8u1ubuntu1.14.04.1~14.04.4
Use lts-xenial stack. Build only guest additions (LP: #1424769).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: ConsoleImpl2.cpp $ */
 
2
/** @file
 
3
 * VBox Console COM Class implementation - VM Configuration Bits.
 
4
 *
 
5
 * @remark  We've split out the code that the 64-bit VC++ v8 compiler finds
 
6
 *          problematic to optimize so we can disable optimizations and later,
 
7
 *          perhaps, find a real solution for it (like rewriting the code and
 
8
 *          to stop resemble a tonne of spaghetti).
 
9
 */
 
10
 
 
11
/*
 
12
 * Copyright (C) 2006-2013 Oracle Corporation
 
13
 *
 
14
 * This file is part of VirtualBox Open Source Edition (OSE), as
 
15
 * available from http://www.virtualbox.org. This file is free software;
 
16
 * you can redistribute it and/or modify it under the terms of the GNU
 
17
 * General Public License (GPL) as published by the Free Software
 
18
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 
19
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 
20
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 
21
 */
 
22
 
 
23
/*******************************************************************************
 
24
*   Header Files                                                               *
 
25
*******************************************************************************/
 
26
// for some reason Windows burns in sdk\...\winsock.h if this isn't included first
 
27
#include "VBox/com/ptr.h"
 
28
 
 
29
#include "ConsoleImpl.h"
 
30
#include "DisplayImpl.h"
 
31
#ifdef VBOX_WITH_GUEST_CONTROL
 
32
# include "GuestImpl.h"
 
33
#endif
 
34
#ifdef VBOX_WITH_DRAG_AND_DROP
 
35
# include "GuestDnDImpl.h"
 
36
#endif
 
37
#include "VMMDev.h"
 
38
#include "Global.h"
 
39
#ifdef VBOX_WITH_PCI_PASSTHROUGH
 
40
# include "PCIRawDevImpl.h"
 
41
#endif
 
42
 
 
43
// generated header
 
44
#include "SchemaDefs.h"
 
45
 
 
46
#include "AutoCaller.h"
 
47
#include "Logging.h"
 
48
 
 
49
#include <iprt/base64.h>
 
50
#include <iprt/buildconfig.h>
 
51
#include <iprt/ctype.h>
 
52
#include <iprt/dir.h>
 
53
#include <iprt/file.h>
 
54
#include <iprt/param.h>
 
55
#include <iprt/path.h>
 
56
#include <iprt/string.h>
 
57
#include <iprt/system.h>
 
58
#include <iprt/cpp/exception.h>
 
59
#if 0 /* enable to play with lots of memory. */
 
60
# include <iprt/env.h>
 
61
#endif
 
62
#include <iprt/stream.h>
 
63
 
 
64
#include <VBox/vmm/vmapi.h>
 
65
#include <VBox/err.h>
 
66
#include <VBox/param.h>
 
67
#include <VBox/vmm/pdmapi.h> /* For PDMR3DriverAttach/PDMR3DriverDetach */
 
68
#include <VBox/version.h>
 
69
#include <VBox/HostServices/VBoxClipboardSvc.h>
 
70
#ifdef VBOX_WITH_CROGL
 
71
# include <VBox/HostServices/VBoxCrOpenGLSvc.h>
 
72
#include <VBox/VBoxOGLTest.h>
 
73
#endif
 
74
#ifdef VBOX_WITH_GUEST_PROPS
 
75
# include <VBox/HostServices/GuestPropertySvc.h>
 
76
# include <VBox/com/defs.h>
 
77
# include <VBox/com/array.h>
 
78
# include "HGCM.h" /** @todo it should be possible to register a service
 
79
                          * extension using a VMMDev callback. */
 
80
# include <vector>
 
81
#endif /* VBOX_WITH_GUEST_PROPS */
 
82
#include <VBox/intnet.h>
 
83
 
 
84
#include <VBox/com/com.h>
 
85
#include <VBox/com/string.h>
 
86
#include <VBox/com/array.h>
 
87
 
 
88
#ifdef VBOX_WITH_NETFLT
 
89
# if defined(RT_OS_SOLARIS)
 
90
#  include <zone.h>
 
91
# elif defined(RT_OS_LINUX)
 
92
#  include <unistd.h>
 
93
#  include <sys/ioctl.h>
 
94
#  include <sys/socket.h>
 
95
#  include <linux/types.h>
 
96
#  include <linux/if.h>
 
97
#  include <linux/wireless.h>
 
98
# elif defined(RT_OS_FREEBSD)
 
99
#  include <unistd.h>
 
100
#  include <sys/types.h>
 
101
#  include <sys/ioctl.h>
 
102
#  include <sys/socket.h>
 
103
#  include <net/if.h>
 
104
#  include <net80211/ieee80211_ioctl.h>
 
105
# endif
 
106
# if defined(RT_OS_WINDOWS)
 
107
#  include <VBox/VBoxNetCfg-win.h>
 
108
#  include <Ntddndis.h>
 
109
#  include <devguid.h>
 
110
# else
 
111
#  include <HostNetworkInterfaceImpl.h>
 
112
#  include <netif.h>
 
113
#  include <stdlib.h>
 
114
# endif
 
115
#endif /* VBOX_WITH_NETFLT */
 
116
 
 
117
#include "NetworkServiceRunner.h"
 
118
#include "BusAssignmentManager.h"
 
119
#ifdef VBOX_WITH_EXTPACK
 
120
# include "ExtPackManagerImpl.h"
 
121
#endif
 
122
 
 
123
 
 
124
/*******************************************************************************
 
125
*   Internal Functions                                                         *
 
126
*******************************************************************************/
 
127
static Utf8Str *GetExtraDataBoth(IVirtualBox *pVirtualBox, IMachine *pMachine, const char *pszName, Utf8Str *pStrValue);
 
128
 
 
129
 
 
130
/* Darwin compile kludge */
 
131
#undef PVM
 
132
 
 
133
/* Comment out the following line to remove VMWare compatibility hack. */
 
134
#define VMWARE_NET_IN_SLOT_11
 
135
 
 
136
/**
 
137
 * Translate IDE StorageControllerType_T to string representation.
 
138
 */
 
139
const char* controllerString(StorageControllerType_T enmType)
 
140
{
 
141
    switch (enmType)
 
142
    {
 
143
        case StorageControllerType_PIIX3:
 
144
            return "PIIX3";
 
145
        case StorageControllerType_PIIX4:
 
146
            return "PIIX4";
 
147
        case StorageControllerType_ICH6:
 
148
            return "ICH6";
 
149
        default:
 
150
            return "Unknown";
 
151
    }
 
152
}
 
153
 
 
154
/**
 
155
 * Simple class for storing network boot information.
 
156
 */
 
157
struct BootNic
 
158
{
 
159
    ULONG          mInstance;
 
160
    PCIBusAddress  mPCIAddress;
 
161
 
 
162
    ULONG          mBootPrio;
 
163
    bool operator < (const BootNic &rhs) const
 
164
    {
 
165
        ULONG lval = mBootPrio     - 1; /* 0 will wrap around and get the lowest priority. */
 
166
        ULONG rval = rhs.mBootPrio - 1;
 
167
        return lval < rval; /* Zero compares as highest number (lowest prio). */
 
168
    }
 
169
};
 
170
 
 
171
static int findEfiRom(IVirtualBox* vbox, FirmwareType_T aFirmwareType, Utf8Str *pEfiRomFile)
 
172
{
 
173
    Bstr aFilePath, empty;
 
174
    BOOL fPresent = FALSE;
 
175
    HRESULT hrc = vbox->CheckFirmwarePresent(aFirmwareType, empty.raw(),
 
176
                                             empty.asOutParam(), aFilePath.asOutParam(), &fPresent);
 
177
    AssertComRCReturn(hrc, Global::vboxStatusCodeFromCOM(hrc));
 
178
 
 
179
    if (!fPresent)
 
180
    {
 
181
        LogRel(("Failed to find an EFI ROM file.\n"));
 
182
        return VERR_FILE_NOT_FOUND;
 
183
    }
 
184
 
 
185
    *pEfiRomFile = Utf8Str(aFilePath);
 
186
 
 
187
    return VINF_SUCCESS;
 
188
}
 
189
 
 
190
/**
 
191
 * @throws HRESULT on extra data retrival error.
 
192
 */
 
193
static int getSmcDeviceKey(IVirtualBox *pVirtualBox, IMachine *pMachine, Utf8Str *pStrKey, bool *pfGetKeyFromRealSMC)
 
194
{
 
195
    *pfGetKeyFromRealSMC = false;
 
196
 
 
197
    /*
 
198
     * The extra data takes precedence (if non-zero).
 
199
     */
 
200
    GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/SmcDeviceKey", pStrKey);
 
201
    if (pStrKey->isNotEmpty())
 
202
        return VINF_SUCCESS;
 
203
 
 
204
#ifdef RT_OS_DARWIN
 
205
 
 
206
    /*
 
207
     * Work done in EFI/DevSmc
 
208
     */
 
209
    *pfGetKeyFromRealSMC = true;
 
210
    int rc = VINF_SUCCESS;
 
211
 
 
212
#else
 
213
    /*
 
214
     * Is it apple hardware in bootcamp?
 
215
     */
 
216
    /** @todo implement + test RTSYSDMISTR_MANUFACTURER on all hosts.
 
217
     *        Currently falling back on the product name. */
 
218
    char szManufacturer[256];
 
219
    szManufacturer[0] = '\0';
 
220
    RTSystemQueryDmiString(RTSYSDMISTR_MANUFACTURER, szManufacturer, sizeof(szManufacturer));
 
221
    if (szManufacturer[0] != '\0')
 
222
    {
 
223
        if (   !strcmp(szManufacturer, "Apple Computer, Inc.")
 
224
            || !strcmp(szManufacturer, "Apple Inc.")
 
225
            )
 
226
            *pfGetKeyFromRealSMC = true;
 
227
    }
 
228
    else
 
229
    {
 
230
        char szProdName[256];
 
231
        szProdName[0] = '\0';
 
232
        RTSystemQueryDmiString(RTSYSDMISTR_PRODUCT_NAME, szProdName, sizeof(szProdName));
 
233
        if (   (   !strncmp(szProdName, RT_STR_TUPLE("Mac"))
 
234
                || !strncmp(szProdName, RT_STR_TUPLE("iMac"))
 
235
                || !strncmp(szProdName, RT_STR_TUPLE("iMac"))
 
236
                || !strncmp(szProdName, RT_STR_TUPLE("Xserve"))
 
237
               )
 
238
            && !strchr(szProdName, ' ')                             /* no spaces */
 
239
            && RT_C_IS_DIGIT(szProdName[strlen(szProdName) - 1])    /* version number */
 
240
           )
 
241
            *pfGetKeyFromRealSMC = true;
 
242
    }
 
243
 
 
244
    int rc = VINF_SUCCESS;
 
245
#endif
 
246
 
 
247
    return rc;
 
248
}
 
249
 
 
250
 
 
251
/*
 
252
 * VC++ 8 / amd64 has some serious trouble with the next functions.
 
253
 * As a temporary measure, we'll drop global optimizations.
 
254
 */
 
255
#if defined(_MSC_VER) && defined(RT_ARCH_AMD64)
 
256
# pragma optimize("g", off)
 
257
#endif
 
258
 
 
259
static const char *const g_apszIDEDrives[4] =
 
260
    { "PrimaryMaster", "PrimarySlave", "SecondaryMaster", "SecondarySlave" };
 
261
 
 
262
class ConfigError : public RTCError
 
263
{
 
264
public:
 
265
 
 
266
    ConfigError(const char *pcszFunction,
 
267
                int vrc,
 
268
                const char *pcszName)
 
269
        : RTCError(Utf8StrFmt("%s failed: rc=%Rrc, pcszName=%s", pcszFunction, vrc, pcszName)),
 
270
          m_vrc(vrc)
 
271
    {
 
272
        AssertMsgFailed(("%s\n", what())); // in strict mode, hit a breakpoint here
 
273
    }
 
274
 
 
275
    int m_vrc;
 
276
};
 
277
 
 
278
 
 
279
/**
 
280
 * Helper that calls CFGMR3InsertString and throws an RTCError if that
 
281
 * fails (C-string variant).
 
282
 * @param   pParent         See CFGMR3InsertStringN.
 
283
 * @param   pcszNodeName    See CFGMR3InsertStringN.
 
284
 * @param   pcszValue       The string value.
 
285
 */
 
286
static void InsertConfigString(PCFGMNODE pNode,
 
287
                               const char *pcszName,
 
288
                               const char *pcszValue)
 
289
{
 
290
    int vrc = CFGMR3InsertString(pNode,
 
291
                                 pcszName,
 
292
                                 pcszValue);
 
293
    if (RT_FAILURE(vrc))
 
294
        throw ConfigError("CFGMR3InsertString", vrc, pcszName);
 
295
}
 
296
 
 
297
/**
 
298
 * Helper that calls CFGMR3InsertString and throws an RTCError if that
 
299
 * fails (Utf8Str variant).
 
300
 * @param   pParent         See CFGMR3InsertStringN.
 
301
 * @param   pcszNodeName    See CFGMR3InsertStringN.
 
302
 * @param   rStrValue       The string value.
 
303
 */
 
304
static void InsertConfigString(PCFGMNODE pNode,
 
305
                               const char *pcszName,
 
306
                               const Utf8Str &rStrValue)
 
307
{
 
308
    int vrc = CFGMR3InsertStringN(pNode,
 
309
                                  pcszName,
 
310
                                  rStrValue.c_str(),
 
311
                                  rStrValue.length());
 
312
    if (RT_FAILURE(vrc))
 
313
        throw ConfigError("CFGMR3InsertStringLengthKnown", vrc, pcszName);
 
314
}
 
315
 
 
316
/**
 
317
 * Helper that calls CFGMR3InsertString and throws an RTCError if that
 
318
 * fails (Bstr variant).
 
319
 *
 
320
 * @param   pParent         See CFGMR3InsertStringN.
 
321
 * @param   pcszNodeName    See CFGMR3InsertStringN.
 
322
 * @param   rBstrValue       The string value.
 
323
 */
 
324
static void InsertConfigString(PCFGMNODE pNode,
 
325
                               const char *pcszName,
 
326
                               const Bstr &rBstrValue)
 
327
{
 
328
    InsertConfigString(pNode, pcszName, Utf8Str(rBstrValue));
 
329
}
 
330
 
 
331
/**
 
332
 * Helper that calls CFGMR3InsertBytes and throws an RTCError if that fails.
 
333
 *
 
334
 * @param   pNode           See CFGMR3InsertBytes.
 
335
 * @param   pcszName        See CFGMR3InsertBytes.
 
336
 * @param   pvBytes         See CFGMR3InsertBytes.
 
337
 * @param   cbBytes         See CFGMR3InsertBytes.
 
338
 */
 
339
static void InsertConfigBytes(PCFGMNODE pNode,
 
340
                              const char *pcszName,
 
341
                              const void *pvBytes,
 
342
                              size_t cbBytes)
 
343
{
 
344
    int vrc = CFGMR3InsertBytes(pNode,
 
345
                                pcszName,
 
346
                                pvBytes,
 
347
                                cbBytes);
 
348
    if (RT_FAILURE(vrc))
 
349
        throw ConfigError("CFGMR3InsertBytes", vrc, pcszName);
 
350
}
 
351
 
 
352
/**
 
353
 * Helper that calls CFGMR3InsertInteger and throws an RTCError if that
 
354
 * fails.
 
355
 *
 
356
 * @param   pNode           See CFGMR3InsertInteger.
 
357
 * @param   pcszName        See CFGMR3InsertInteger.
 
358
 * @param   u64Integer      See CFGMR3InsertInteger.
 
359
 */
 
360
static void InsertConfigInteger(PCFGMNODE pNode,
 
361
                                const char *pcszName,
 
362
                                uint64_t u64Integer)
 
363
{
 
364
    int vrc = CFGMR3InsertInteger(pNode,
 
365
                                  pcszName,
 
366
                                  u64Integer);
 
367
    if (RT_FAILURE(vrc))
 
368
        throw ConfigError("CFGMR3InsertInteger", vrc, pcszName);
 
369
}
 
370
 
 
371
/**
 
372
 * Helper that calls CFGMR3InsertNode and throws an RTCError if that fails.
 
373
 *
 
374
 * @param   pNode           See CFGMR3InsertNode.
 
375
 * @param   pcszName        See CFGMR3InsertNode.
 
376
 * @param   ppChild         See CFGMR3InsertNode.
 
377
 */
 
378
static void InsertConfigNode(PCFGMNODE pNode,
 
379
                             const char *pcszName,
 
380
                             PCFGMNODE *ppChild)
 
381
{
 
382
    int vrc = CFGMR3InsertNode(pNode, pcszName, ppChild);
 
383
    if (RT_FAILURE(vrc))
 
384
        throw ConfigError("CFGMR3InsertNode", vrc, pcszName);
 
385
}
 
386
 
 
387
/**
 
388
 * Helper that calls CFGMR3RemoveValue and throws an RTCError if that fails.
 
389
 *
 
390
 * @param   pNode           See CFGMR3RemoveValue.
 
391
 * @param   pcszName        See CFGMR3RemoveValue.
 
392
 */
 
393
static void RemoveConfigValue(PCFGMNODE pNode,
 
394
                              const char *pcszName)
 
395
{
 
396
    int vrc = CFGMR3RemoveValue(pNode, pcszName);
 
397
    if (RT_FAILURE(vrc))
 
398
        throw ConfigError("CFGMR3RemoveValue", vrc, pcszName);
 
399
}
 
400
 
 
401
/**
 
402
 * Gets an extra data value, consulting both machine and global extra data.
 
403
 *
 
404
 * @throws  HRESULT on failure
 
405
 * @returns pStrValue for the callers convenience.
 
406
 * @param   pVirtualBox     Pointer to the IVirtualBox interface.
 
407
 * @param   pMachine        Pointer to the IMachine interface.
 
408
 * @param   pszName         The value to get.
 
409
 * @param   pStrValue       Where to return it's value (empty string if not
 
410
 *                          found).
 
411
 */
 
412
static Utf8Str *GetExtraDataBoth(IVirtualBox *pVirtualBox, IMachine *pMachine, const char *pszName, Utf8Str *pStrValue)
 
413
{
 
414
    pStrValue->setNull();
 
415
 
 
416
    Bstr bstrName(pszName);
 
417
    Bstr bstrValue;
 
418
    HRESULT hrc = pMachine->GetExtraData(bstrName.raw(), bstrValue.asOutParam());
 
419
    if (FAILED(hrc))
 
420
        throw hrc;
 
421
    if (bstrValue.isEmpty())
 
422
    {
 
423
        hrc = pVirtualBox->GetExtraData(bstrName.raw(), bstrValue.asOutParam());
 
424
        if (FAILED(hrc))
 
425
            throw hrc;
 
426
    }
 
427
 
 
428
    if (bstrValue.isNotEmpty())
 
429
        *pStrValue = bstrValue;
 
430
    return pStrValue;
 
431
}
 
432
 
 
433
 
 
434
/** Helper that finds out the next HBA port used
 
435
 */
 
436
static LONG GetNextUsedPort(LONG aPortUsed[30], LONG lBaseVal, uint32_t u32Size)
 
437
{
 
438
    LONG lNextPortUsed = 30;
 
439
    for (size_t j = 0; j < u32Size; ++j)
 
440
    {
 
441
        if (   aPortUsed[j] >  lBaseVal
 
442
            && aPortUsed[j] <= lNextPortUsed)
 
443
           lNextPortUsed = aPortUsed[j];
 
444
    }
 
445
    return lNextPortUsed;
 
446
}
 
447
 
 
448
#define MAX_BIOS_LUN_COUNT   4
 
449
 
 
450
static int SetBiosDiskInfo(ComPtr<IMachine> pMachine, PCFGMNODE pCfg, PCFGMNODE pBiosCfg,
 
451
                           Bstr controllerName, const char * const s_apszBiosConfig[4])
 
452
{
 
453
    HRESULT             hrc;
 
454
#define MAX_DEVICES     30
 
455
#define H()     AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
 
456
 
 
457
    LONG lPortLUN[MAX_BIOS_LUN_COUNT];
 
458
    LONG lPortUsed[MAX_DEVICES];
 
459
    uint32_t u32HDCount = 0;
 
460
 
 
461
    /* init to max value */
 
462
    lPortLUN[0] = MAX_DEVICES;
 
463
 
 
464
    com::SafeIfaceArray<IMediumAttachment> atts;
 
465
    hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),
 
466
                                        ComSafeArrayAsOutParam(atts));  H();
 
467
    size_t uNumAttachments = atts.size();
 
468
    if (uNumAttachments > MAX_DEVICES)
 
469
    {
 
470
        LogRel(("Number of Attachments > Max=%d.\n", uNumAttachments));
 
471
        uNumAttachments = MAX_DEVICES;
 
472
    }
 
473
 
 
474
    /* Find the relevant ports/IDs, i.e the ones to which a HD is attached. */
 
475
    for (size_t j = 0; j < uNumAttachments; ++j)
 
476
    {
 
477
        IMediumAttachment *pMediumAtt = atts[j];
 
478
        LONG lPortNum = 0;
 
479
        hrc = pMediumAtt->COMGETTER(Port)(&lPortNum);                   H();
 
480
        if (SUCCEEDED(hrc))
 
481
        {
 
482
            DeviceType_T lType;
 
483
            hrc = pMediumAtt->COMGETTER(Type)(&lType);                    H();
 
484
            if (SUCCEEDED(hrc) && lType == DeviceType_HardDisk)
 
485
            {
 
486
                /* find min port number used for HD */
 
487
                if (lPortNum < lPortLUN[0])
 
488
                    lPortLUN[0] = lPortNum;
 
489
                lPortUsed[u32HDCount++] = lPortNum;
 
490
                LogFlowFunc(("HD port Count=%d\n", u32HDCount));
 
491
            }
 
492
 
 
493
            /* Configure the hotpluggable flag for the port. */
 
494
            BOOL fHotPluggable = FALSE;
 
495
            hrc = pMediumAtt->COMGETTER(HotPluggable)(&fHotPluggable); H();
 
496
            if (SUCCEEDED(hrc))
 
497
            {
 
498
                PCFGMNODE pPortCfg;
 
499
                char szName[24];
 
500
                RTStrPrintf(szName, sizeof(szName), "Port%d", lPortNum);
 
501
 
 
502
                InsertConfigNode(pCfg, szName, &pPortCfg);
 
503
                InsertConfigInteger(pPortCfg, "Hotpluggable", fHotPluggable ? 1 : 0);
 
504
            }
 
505
         }
 
506
    }
 
507
 
 
508
 
 
509
    /* Pick only the top 4 used HD Ports as CMOS doesn't have space
 
510
     * to save details for all 30 ports
 
511
     */
 
512
    uint32_t u32MaxPortCount = MAX_BIOS_LUN_COUNT;
 
513
    if (u32HDCount < MAX_BIOS_LUN_COUNT)
 
514
        u32MaxPortCount = u32HDCount;
 
515
    for (size_t j = 1; j < u32MaxPortCount; j++)
 
516
        lPortLUN[j] = GetNextUsedPort(lPortUsed,
 
517
                                      lPortLUN[j-1],
 
518
                                       u32HDCount);
 
519
    if (pBiosCfg)
 
520
    {
 
521
        for (size_t j = 0; j < u32MaxPortCount; j++)
 
522
        {
 
523
            InsertConfigInteger(pBiosCfg, s_apszBiosConfig[j], lPortLUN[j]);
 
524
            LogFlowFunc(("Top %d HBA ports = %s, %d\n", j, s_apszBiosConfig[j], lPortLUN[j]));
 
525
        }
 
526
    }
 
527
    return VINF_SUCCESS;
 
528
}
 
529
 
 
530
#ifdef VBOX_WITH_PCI_PASSTHROUGH
 
531
HRESULT Console::attachRawPCIDevices(PUVM pUVM, BusAssignmentManager *pBusMgr, PCFGMNODE pDevices)
 
532
{
 
533
    HRESULT hrc = S_OK;
 
534
    PCFGMNODE pInst, pCfg, pLunL0, pLunL1;
 
535
 
 
536
    SafeIfaceArray<IPCIDeviceAttachment> assignments;
 
537
    ComPtr<IMachine> aMachine = machine();
 
538
 
 
539
    hrc = aMachine->COMGETTER(PCIDeviceAssignments)(ComSafeArrayAsOutParam(assignments));
 
540
    if (   hrc != S_OK
 
541
        || assignments.size() < 1)
 
542
        return hrc;
 
543
 
 
544
    /*
 
545
     * PCI passthrough is only available if the proper ExtPack is installed.
 
546
     *
 
547
     * Note. Configuring PCI passthrough here and providing messages about
 
548
     * the missing extpack isn't exactly clean, but it is a necessary evil
 
549
     * to patch over legacy compatability issues introduced by the new
 
550
     * distribution model.
 
551
     */
 
552
# ifdef VBOX_WITH_EXTPACK
 
553
    static const char *s_pszPCIRawExtPackName = "Oracle VM VirtualBox Extension Pack";
 
554
    if (!mptrExtPackManager->isExtPackUsable(s_pszPCIRawExtPackName))
 
555
        /* Always fatal! */
 
556
        return VMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
 
557
                N_("Implementation of the PCI passthrough framework not found!\n"
 
558
                   "The VM cannot be started. To fix this problem, either "
 
559
                   "install the '%s' or disable PCI passthrough via VBoxManage"),
 
560
                s_pszPCIRawExtPackName);
 
561
# endif
 
562
 
 
563
    PCFGMNODE pBridges = CFGMR3GetChild(pDevices, "ich9pcibridge");
 
564
    Assert(pBridges);
 
565
 
 
566
    /* Find required bridges, and add missing ones */
 
567
    for (size_t iDev = 0; iDev < assignments.size(); iDev++)
 
568
    {
 
569
        ComPtr<IPCIDeviceAttachment> assignment = assignments[iDev];
 
570
        LONG guest = 0;
 
571
        PCIBusAddress GuestPCIAddress;
 
572
 
 
573
        assignment->COMGETTER(GuestAddress)(&guest);
 
574
        GuestPCIAddress.fromLong(guest);
 
575
        Assert(GuestPCIAddress.valid());
 
576
 
 
577
        if (GuestPCIAddress.miBus > 0)
 
578
        {
 
579
            int iBridgesMissed = 0;
 
580
            int iBase = GuestPCIAddress.miBus - 1;
 
581
 
 
582
            while (!pBusMgr->hasPCIDevice("ich9pcibridge", iBase) && iBase > 0)
 
583
            {
 
584
                iBridgesMissed++; iBase--;
 
585
            }
 
586
            iBase++;
 
587
 
 
588
            for (int iBridge = 0; iBridge < iBridgesMissed; iBridge++)
 
589
            {
 
590
                InsertConfigNode(pBridges, Utf8StrFmt("%d", iBase + iBridge).c_str(), &pInst);
 
591
                InsertConfigInteger(pInst, "Trusted",              1);
 
592
                hrc = pBusMgr->assignPCIDevice("ich9pcibridge", pInst);
 
593
            }
 
594
        }
 
595
    }
 
596
 
 
597
    /* Now actually add devices */
 
598
    PCFGMNODE pPCIDevs = NULL;
 
599
 
 
600
    if (assignments.size() > 0)
 
601
    {
 
602
        InsertConfigNode(pDevices, "pciraw",  &pPCIDevs);
 
603
 
 
604
        PCFGMNODE pRoot = CFGMR3GetParent(pDevices); Assert(pRoot);
 
605
 
 
606
        /* Tell PGM to tell GPCIRaw about guest mappings. */
 
607
        CFGMR3InsertNode(pRoot, "PGM", NULL);
 
608
        InsertConfigInteger(CFGMR3GetChild(pRoot, "PGM"), "PciPassThrough", 1);
 
609
 
 
610
        /*
 
611
         * Currently, using IOMMU needed for PCI passthrough
 
612
         * requires RAM preallocation.
 
613
         */
 
614
        /** @todo: check if we can lift this requirement */
 
615
        CFGMR3RemoveValue(pRoot, "RamPreAlloc");
 
616
        InsertConfigInteger(pRoot, "RamPreAlloc", 1);
 
617
    }
 
618
 
 
619
    for (size_t iDev = 0; iDev < assignments.size(); iDev++)
 
620
    {
 
621
        PCIBusAddress HostPCIAddress, GuestPCIAddress;
 
622
        ComPtr<IPCIDeviceAttachment> assignment = assignments[iDev];
 
623
        LONG host, guest;
 
624
        Bstr aDevName;
 
625
 
 
626
        assignment->COMGETTER(HostAddress)(&host);
 
627
        assignment->COMGETTER(GuestAddress)(&guest);
 
628
        assignment->COMGETTER(Name)(aDevName.asOutParam());
 
629
 
 
630
        InsertConfigNode(pPCIDevs, Utf8StrFmt("%d", iDev).c_str(), &pInst);
 
631
        InsertConfigInteger(pInst, "Trusted", 1);
 
632
 
 
633
        HostPCIAddress.fromLong(host);
 
634
        Assert(HostPCIAddress.valid());
 
635
        InsertConfigNode(pInst,        "Config",  &pCfg);
 
636
        InsertConfigString(pCfg,       "DeviceName",  aDevName);
 
637
 
 
638
        InsertConfigInteger(pCfg,      "DetachHostDriver",  1);
 
639
        InsertConfigInteger(pCfg,      "HostPCIBusNo",      HostPCIAddress.miBus);
 
640
        InsertConfigInteger(pCfg,      "HostPCIDeviceNo",   HostPCIAddress.miDevice);
 
641
        InsertConfigInteger(pCfg,      "HostPCIFunctionNo", HostPCIAddress.miFn);
 
642
 
 
643
        GuestPCIAddress.fromLong(guest);
 
644
        Assert(GuestPCIAddress.valid());
 
645
        hrc = pBusMgr->assignHostPCIDevice("pciraw", pInst, HostPCIAddress, GuestPCIAddress, true);
 
646
        if (hrc != S_OK)
 
647
            return hrc;
 
648
 
 
649
        InsertConfigInteger(pCfg,      "GuestPCIBusNo",      GuestPCIAddress.miBus);
 
650
        InsertConfigInteger(pCfg,      "GuestPCIDeviceNo",   GuestPCIAddress.miDevice);
 
651
        InsertConfigInteger(pCfg,      "GuestPCIFunctionNo", GuestPCIAddress.miFn);
 
652
 
 
653
        /* the driver */
 
654
        InsertConfigNode(pInst,        "LUN#0",   &pLunL0);
 
655
        InsertConfigString(pLunL0,     "Driver", "pciraw");
 
656
        InsertConfigNode(pLunL0,       "AttachedDriver", &pLunL1);
 
657
 
 
658
        /* the Main driver */
 
659
        InsertConfigString(pLunL1,     "Driver", "MainPciRaw");
 
660
        InsertConfigNode(pLunL1,       "Config", &pCfg);
 
661
        PCIRawDev* pMainDev = new PCIRawDev(this);
 
662
        InsertConfigInteger(pCfg,      "Object", (uintptr_t)pMainDev);
 
663
    }
 
664
 
 
665
    return hrc;
 
666
}
 
667
#endif
 
668
 
 
669
 
 
670
void Console::attachStatusDriver(PCFGMNODE pCtlInst, PPDMLED *papLeds,
 
671
                                 uint64_t uFirst, uint64_t uLast,
 
672
                                 Console::MediumAttachmentMap *pmapMediumAttachments,
 
673
                                 const char *pcszDevice, unsigned uInstance)
 
674
{
 
675
    PCFGMNODE pLunL0, pCfg;
 
676
    InsertConfigNode(pCtlInst,  "LUN#999", &pLunL0);
 
677
    InsertConfigString(pLunL0,  "Driver",               "MainStatus");
 
678
    InsertConfigNode(pLunL0,    "Config", &pCfg);
 
679
    InsertConfigInteger(pCfg,   "papLeds", (uintptr_t)papLeds);
 
680
    if (pmapMediumAttachments)
 
681
    {
 
682
        InsertConfigInteger(pCfg,   "pmapMediumAttachments", (uintptr_t)pmapMediumAttachments);
 
683
        InsertConfigInteger(pCfg,   "pConsole", (uintptr_t)this);
 
684
        AssertPtr(pcszDevice);
 
685
        Utf8Str deviceInstance = Utf8StrFmt("%s/%u", pcszDevice, uInstance);
 
686
        InsertConfigString(pCfg,    "DeviceInstance", deviceInstance.c_str());
 
687
    }
 
688
    InsertConfigInteger(pCfg,   "First",    uFirst);
 
689
    InsertConfigInteger(pCfg,   "Last",     uLast);
 
690
}
 
691
 
 
692
 
 
693
/**
 
694
 *  Construct the VM configuration tree (CFGM).
 
695
 *
 
696
 *  This is a callback for VMR3Create() call. It is called from CFGMR3Init()
 
697
 *  in the emulation thread (EMT). Any per thread COM/XPCOM initialization
 
698
 *  is done here.
 
699
 *
 
700
 *  @param   pUVM                The user mode VM handle.
 
701
 *  @param   pVM                 The cross context VM handle.
 
702
 *  @param   pvConsole           Pointer to the VMPowerUpTask object.
 
703
 *  @return  VBox status code.
 
704
 *
 
705
 *  @note Locks the Console object for writing.
 
706
 */
 
707
DECLCALLBACK(int) Console::configConstructor(PUVM pUVM, PVM pVM, void *pvConsole)
 
708
{
 
709
    LogFlowFuncEnter();
 
710
 
 
711
    AssertReturn(pvConsole, VERR_INVALID_POINTER);
 
712
    ComObjPtr<Console> pConsole = static_cast<Console *>(pvConsole);
 
713
 
 
714
    AutoCaller autoCaller(pConsole);
 
715
    AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED);
 
716
 
 
717
    /* lock the console because we widely use internal fields and methods */
 
718
    AutoWriteLock alock(pConsole COMMA_LOCKVAL_SRC_POS);
 
719
 
 
720
    /*
 
721
     * Set the VM handle and do the rest of the job in an worker method so we
 
722
     * can easily reset the VM handle on failure.
 
723
     */
 
724
    pConsole->mpUVM = pUVM;
 
725
    VMR3RetainUVM(pUVM);
 
726
    int vrc;
 
727
    try
 
728
    {
 
729
        vrc = pConsole->configConstructorInner(pUVM, pVM, &alock);
 
730
    }
 
731
    catch (...)
 
732
    {
 
733
        vrc = VERR_UNEXPECTED_EXCEPTION;
 
734
    }
 
735
    if (RT_FAILURE(vrc))
 
736
    {
 
737
        pConsole->mpUVM = NULL;
 
738
        VMR3ReleaseUVM(pUVM);
 
739
    }
 
740
 
 
741
    return vrc;
 
742
}
 
743
 
 
744
 
 
745
/**
 
746
 * Worker for configConstructor.
 
747
 *
 
748
 * @return  VBox status code.
 
749
 * @param   pUVM        The user mode VM handle.
 
750
 * @param   pVM         The cross context VM handle.
 
751
 * @param   pAlock      The automatic lock instance.  This is for when we have
 
752
 *                      to leave it in order to avoid deadlocks (ext packs and
 
753
 *                      more).
 
754
 */
 
755
int Console::configConstructorInner(PUVM pUVM, PVM pVM, AutoWriteLock *pAlock)
 
756
{
 
757
    VMMDev         *pVMMDev   = m_pVMMDev; Assert(pVMMDev);
 
758
    ComPtr<IMachine> pMachine = machine();
 
759
 
 
760
    int             rc;
 
761
    HRESULT         hrc;
 
762
    Utf8Str         strTmp;
 
763
    Bstr            bstr;
 
764
 
 
765
#define H()         AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
 
766
 
 
767
    /*
 
768
     * Get necessary objects and frequently used parameters.
 
769
     */
 
770
    ComPtr<IVirtualBox> virtualBox;
 
771
    hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam());                             H();
 
772
 
 
773
    ComPtr<IHost> host;
 
774
    hrc = virtualBox->COMGETTER(Host)(host.asOutParam());                                   H();
 
775
 
 
776
    ComPtr<ISystemProperties> systemProperties;
 
777
    hrc = virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam());           H();
 
778
 
 
779
    ComPtr<IBIOSSettings> biosSettings;
 
780
    hrc = pMachine->COMGETTER(BIOSSettings)(biosSettings.asOutParam());                     H();
 
781
 
 
782
    hrc = pMachine->COMGETTER(HardwareUUID)(bstr.asOutParam());                             H();
 
783
    RTUUID HardwareUuid;
 
784
    rc = RTUuidFromUtf16(&HardwareUuid, bstr.raw());
 
785
    AssertRCReturn(rc, rc);
 
786
 
 
787
    ULONG cRamMBs;
 
788
    hrc = pMachine->COMGETTER(MemorySize)(&cRamMBs);                                        H();
 
789
#if 0 /* enable to play with lots of memory. */
 
790
    if (RTEnvExist("VBOX_RAM_SIZE"))
 
791
        cRamMBs = RTStrToUInt64(RTEnvGet("VBOX_RAM_SIZE"));
 
792
#endif
 
793
    uint64_t const cbRam   = cRamMBs * (uint64_t)_1M;
 
794
    uint32_t cbRamHole     = MM_RAM_HOLE_SIZE_DEFAULT;
 
795
    uint64_t uMcfgBase     = 0;
 
796
    uint32_t cbMcfgLength  = 0;
 
797
 
 
798
    ChipsetType_T chipsetType;
 
799
    hrc = pMachine->COMGETTER(ChipsetType)(&chipsetType);                                   H();
 
800
    if (chipsetType == ChipsetType_ICH9)
 
801
    {
 
802
        /* We'd better have 0x10000000 region, to cover 256 buses
 
803
           but this put too much load on hypervisor heap */
 
804
        cbMcfgLength = 0x4000000; //0x10000000;
 
805
        cbRamHole += cbMcfgLength;
 
806
        uMcfgBase = _4G - cbRamHole;
 
807
    }
 
808
 
 
809
    BusAssignmentManager *pBusMgr = mBusMgr = BusAssignmentManager::createInstance(chipsetType);
 
810
 
 
811
    ULONG cCpus = 1;
 
812
    hrc = pMachine->COMGETTER(CPUCount)(&cCpus);                                            H();
 
813
 
 
814
    ULONG ulCpuExecutionCap = 100;
 
815
    hrc = pMachine->COMGETTER(CPUExecutionCap)(&ulCpuExecutionCap);                         H();
 
816
 
 
817
    Bstr osTypeId;
 
818
    hrc = pMachine->COMGETTER(OSTypeId)(osTypeId.asOutParam());                             H();
 
819
    LogRel(("Guest OS type: '%s'\n", Utf8Str(osTypeId).c_str()));
 
820
 
 
821
    BOOL fIOAPIC;
 
822
    hrc = biosSettings->COMGETTER(IOAPICEnabled)(&fIOAPIC);                                 H();
 
823
 
 
824
    ComPtr<IGuestOSType> guestOSType;
 
825
    hrc = virtualBox->GetGuestOSType(osTypeId.raw(), guestOSType.asOutParam());             H();
 
826
 
 
827
    Bstr guestTypeFamilyId;
 
828
    hrc = guestOSType->COMGETTER(FamilyId)(guestTypeFamilyId.asOutParam());                 H();
 
829
    BOOL fOsXGuest = guestTypeFamilyId == Bstr("MacOS");
 
830
 
 
831
    ULONG maxNetworkAdapters;
 
832
    hrc = systemProperties->GetMaxNetworkAdapters(chipsetType, &maxNetworkAdapters);        H();
 
833
    /*
 
834
     * Get root node first.
 
835
     * This is the only node in the tree.
 
836
     */
 
837
    PCFGMNODE pRoot = CFGMR3GetRootU(pUVM);
 
838
    Assert(pRoot);
 
839
 
 
840
    // InsertConfigString throws
 
841
    try
 
842
    {
 
843
 
 
844
        /*
 
845
         * Set the root (and VMM) level values.
 
846
         */
 
847
        hrc = pMachine->COMGETTER(Name)(bstr.asOutParam());                                 H();
 
848
        InsertConfigString(pRoot,  "Name",                 bstr);
 
849
        InsertConfigBytes(pRoot,   "UUID", &HardwareUuid, sizeof(HardwareUuid));
 
850
        InsertConfigInteger(pRoot, "RamSize",              cbRam);
 
851
        InsertConfigInteger(pRoot, "RamHoleSize",          cbRamHole);
 
852
        InsertConfigInteger(pRoot, "NumCPUs",              cCpus);
 
853
        InsertConfigInteger(pRoot, "CpuExecutionCap",      ulCpuExecutionCap);
 
854
        InsertConfigInteger(pRoot, "TimerMillies",         10);
 
855
#ifdef VBOX_WITH_RAW_MODE
 
856
        InsertConfigInteger(pRoot, "RawR3Enabled",         1);     /* boolean */
 
857
        InsertConfigInteger(pRoot, "RawR0Enabled",         1);     /* boolean */
 
858
        /** @todo Config: RawR0, PATMEnabled and CSAMEnabled needs attention later. */
 
859
        InsertConfigInteger(pRoot, "PATMEnabled",          1);     /* boolean */
 
860
        InsertConfigInteger(pRoot, "CSAMEnabled",          1);     /* boolean */
 
861
#endif
 
862
 
 
863
#ifdef VBOX_WITH_RAW_RING1
 
864
        if (osTypeId == "QNX")
 
865
        {
 
866
            /* QNX needs special treatment in raw mode due to its use of ring-1. */
 
867
            InsertConfigInteger(pRoot, "RawR1Enabled",     1);     /* boolean */
 
868
        }
 
869
#endif
 
870
 
 
871
        BOOL fPageFusion = FALSE;
 
872
        hrc = pMachine->COMGETTER(PageFusionEnabled)(&fPageFusion);                         H();
 
873
        InsertConfigInteger(pRoot, "PageFusionAllowed",    fPageFusion); /* boolean */
 
874
 
 
875
        /* Not necessary, but makes sure this setting ends up in the release log. */
 
876
        ULONG ulBalloonSize = 0;
 
877
        hrc = pMachine->COMGETTER(MemoryBalloonSize)(&ulBalloonSize);                       H();
 
878
        InsertConfigInteger(pRoot, "MemBalloonSize",       ulBalloonSize);
 
879
 
 
880
        /*
 
881
         * CPUM values.
 
882
         */
 
883
        PCFGMNODE pCPUM;
 
884
        InsertConfigNode(pRoot, "CPUM", &pCPUM);
 
885
 
 
886
        /* cpuid leaf overrides. */
 
887
        static uint32_t const s_auCpuIdRanges[] =
 
888
        {
 
889
            UINT32_C(0x00000000), UINT32_C(0x0000000a),
 
890
            UINT32_C(0x80000000), UINT32_C(0x8000000a)
 
891
        };
 
892
        for (unsigned i = 0; i < RT_ELEMENTS(s_auCpuIdRanges); i += 2)
 
893
            for (uint32_t uLeaf = s_auCpuIdRanges[i]; uLeaf < s_auCpuIdRanges[i + 1]; uLeaf++)
 
894
            {
 
895
                ULONG ulEax, ulEbx, ulEcx, ulEdx;
 
896
                hrc = pMachine->GetCPUIDLeaf(uLeaf, &ulEax, &ulEbx, &ulEcx, &ulEdx);
 
897
                if (SUCCEEDED(hrc))
 
898
                {
 
899
                    PCFGMNODE pLeaf;
 
900
                    InsertConfigNode(pCPUM, Utf8StrFmt("HostCPUID/%RX32", uLeaf).c_str(), &pLeaf);
 
901
 
 
902
                    InsertConfigInteger(pLeaf, "eax", ulEax);
 
903
                    InsertConfigInteger(pLeaf, "ebx", ulEbx);
 
904
                    InsertConfigInteger(pLeaf, "ecx", ulEcx);
 
905
                    InsertConfigInteger(pLeaf, "edx", ulEdx);
 
906
                }
 
907
                else if (hrc != E_INVALIDARG)                                               H();
 
908
            }
 
909
 
 
910
        /* We must limit CPUID count for Windows NT 4, as otherwise it stops
 
911
        with error 0x3e (MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED). */
 
912
        if (osTypeId == "WindowsNT4")
 
913
        {
 
914
            LogRel(("Limiting CPUID leaf count for NT4 guests\n"));
 
915
            InsertConfigInteger(pCPUM, "NT4LeafLimit", true);
 
916
        }
 
917
 
 
918
        /* Expose CMPXCHG16B. Currently a hack. */
 
919
        if (   osTypeId == "Windows81_64"
 
920
            || osTypeId == "Windows2012_64"
 
921
            || osTypeId == "Windows10_64")
 
922
        {
 
923
            LogRel(("Enabling CMPXCHG16B for Windows 8.1 / 2k12 or newer guests\n"));
 
924
            InsertConfigInteger(pCPUM, "CMPXCHG16B", true);
 
925
        }
 
926
 
 
927
        /* Expose extended MWAIT features to Mac OS X guests. */
 
928
        if (fOsXGuest)
 
929
        {
 
930
            LogRel(("Using MWAIT extensions\n"));
 
931
            InsertConfigInteger(pCPUM, "MWaitExtensions", true);
 
932
        }
 
933
 
 
934
        if (fOsXGuest)
 
935
        {
 
936
            InsertConfigInteger(pCPUM, "EnableHVP", 1);
 
937
 
 
938
            /* Fake the CPU family/model so the guest works.  This is partly
 
939
               because older mac releases really doesn't work on newer cpus,
 
940
               and partly because mac os x expects more from systems with newer
 
941
               cpus (MSRs, power features, whatever). */
 
942
            uint32_t uMaxIntelFamilyModelStep = UINT32_MAX;
 
943
            if (   osTypeId == "MacOS"
 
944
                || osTypeId == "MacOS_64")
 
945
                uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482. */
 
946
            else if (   osTypeId == "MacOS106"
 
947
                     || osTypeId == "MacOS106_64")
 
948
                uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */
 
949
            else if (   osTypeId == "MacOS107"
 
950
                     || osTypeId == "MacOS107_64")
 
951
                uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */ /** @todo figure out
 
952
                                                                                what is required here. */
 
953
            else if (   osTypeId == "MacOS108"
 
954
                     || osTypeId == "MacOS108_64")
 
955
                uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */ /** @todo figure out
 
956
                                                                                what is required here. */
 
957
            else if (   osTypeId == "MacOS109"
 
958
                     || osTypeId == "MacOS109_64")
 
959
                uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */ /** @todo figure
 
960
                                                                                out what is required here. */
 
961
            if (uMaxIntelFamilyModelStep != UINT32_MAX)
 
962
                InsertConfigInteger(pCPUM, "MaxIntelFamilyModelStep", uMaxIntelFamilyModelStep);
 
963
        }
 
964
 
 
965
 
 
966
        /* Synthetic CPU */
 
967
        BOOL fSyntheticCpu = false;
 
968
        hrc = pMachine->GetCPUProperty(CPUPropertyType_Synthetic, &fSyntheticCpu);          H();
 
969
        InsertConfigInteger(pCPUM, "SyntheticCpu", fSyntheticCpu);
 
970
 
 
971
        /* Physical Address Extension (PAE) */
 
972
        BOOL fEnablePAE = false;
 
973
        hrc = pMachine->GetCPUProperty(CPUPropertyType_PAE, &fEnablePAE);                   H();
 
974
        InsertConfigInteger(pRoot, "EnablePAE", fEnablePAE);
 
975
 
 
976
 
 
977
        /*
 
978
         * Hardware virtualization extensions.
 
979
         */
 
980
        BOOL fSupportsHwVirtEx;
 
981
        hrc = host->GetProcessorFeature(ProcessorFeature_HWVirtEx, &fSupportsHwVirtEx);     H();
 
982
 
 
983
        BOOL fIsGuest64Bit;
 
984
        hrc = pMachine->GetCPUProperty(CPUPropertyType_LongMode, &fIsGuest64Bit);           H();
 
985
        if (fIsGuest64Bit)
 
986
        {
 
987
            BOOL fSupportsLongMode;
 
988
            hrc = host->GetProcessorFeature(ProcessorFeature_LongMode, &fSupportsLongMode); H();
 
989
            if (!fSupportsLongMode)
 
990
            {
 
991
                LogRel(("WARNING! 64-bit guest type selected but the host CPU does NOT support 64-bit.\n"));
 
992
                fIsGuest64Bit = FALSE;
 
993
            }
 
994
            if (!fSupportsHwVirtEx)
 
995
            {
 
996
                LogRel(("WARNING! 64-bit guest type selected but the host CPU does NOT support HW virtualization.\n"));
 
997
                fIsGuest64Bit = FALSE;
 
998
            }
 
999
        }
 
1000
 
 
1001
        BOOL fHMEnabled;
 
1002
        hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_Enabled, &fHMEnabled);     H();
 
1003
        if (cCpus > 1 && !fHMEnabled)
 
1004
        {
 
1005
            LogRel(("Forced fHMEnabled to TRUE by SMP guest.\n"));
 
1006
            fHMEnabled = TRUE;
 
1007
        }
 
1008
 
 
1009
        BOOL fHMForced;
 
1010
#ifdef VBOX_WITH_RAW_MODE
 
1011
        /* - With more than 4GB PGM will use different RAMRANGE sizes for raw
 
1012
             mode and hv mode to optimize lookup times.
 
1013
           - With more than one virtual CPU, raw-mode isn't a fallback option.
 
1014
           - With a 64-bit guest, raw-mode isn't a fallback option either. */
 
1015
        fHMForced = fHMEnabled
 
1016
                 && (   cbRam + cbRamHole > _4G
 
1017
                     || cCpus > 1
 
1018
                     || fIsGuest64Bit);
 
1019
# ifdef RT_OS_DARWIN
 
1020
        fHMForced = fHMEnabled;
 
1021
# endif
 
1022
        if (fHMForced)
 
1023
        {
 
1024
            if (cbRam + cbRamHole > _4G)
 
1025
                LogRel(("fHMForced=true - Lots of RAM\n"));
 
1026
            if (cCpus > 1)
 
1027
                LogRel(("fHMForced=true - SMP\n"));
 
1028
            if (fIsGuest64Bit)
 
1029
                LogRel(("fHMForced=true - 64-bit guest\n"));
 
1030
# ifdef RT_OS_DARWIN
 
1031
            LogRel(("fHMForced=true - Darwin host\n"));
 
1032
# endif
 
1033
        }
 
1034
#else  /* !VBOX_WITH_RAW_MODE */
 
1035
        fHMEnabled = fHMForced = TRUE;
 
1036
        LogRel(("fHMForced=true - No raw-mode support in this build!\n"));
 
1037
#endif /* !VBOX_WITH_RAW_MODE */
 
1038
        if (!fHMForced) /* No need to query if already forced above. */
 
1039
        {
 
1040
            hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_Force, &fHMForced); H();
 
1041
            if (fHMForced)
 
1042
                LogRel(("fHMForced=true - HWVirtExPropertyType_Force\n"));
 
1043
        }
 
1044
        InsertConfigInteger(pRoot, "HMEnabled", fHMEnabled);
 
1045
 
 
1046
        /* /EM/xzy */
 
1047
        PCFGMNODE pEM;
 
1048
        InsertConfigNode(pRoot, "EM", &pEM);
 
1049
 
 
1050
        /* Triple fault behavior. */
 
1051
        BOOL fTripleFaultReset = false;
 
1052
        hrc = pMachine->GetCPUProperty(CPUPropertyType_TripleFaultReset, &fTripleFaultReset); H();
 
1053
        InsertConfigInteger(pEM, "TripleFaultReset", fTripleFaultReset);
 
1054
 
 
1055
        /* /HM/xzy */
 
1056
        PCFGMNODE pHM;
 
1057
        InsertConfigNode(pRoot, "HM", &pHM);
 
1058
        InsertConfigInteger(pHM, "HMForced", fHMForced);
 
1059
        if (fHMEnabled)
 
1060
        {
 
1061
            /* Indicate whether 64-bit guests are supported or not. */
 
1062
            InsertConfigInteger(pHM, "64bitEnabled", fIsGuest64Bit);
 
1063
#if ARCH_BITS == 32 /* The recompiler must use VBoxREM64 (32-bit host only). */
 
1064
            PCFGMNODE pREM;
 
1065
            InsertConfigNode(pRoot, "REM", &pREM);
 
1066
            InsertConfigInteger(pREM, "64bitEnabled", 1);
 
1067
#endif
 
1068
 
 
1069
            /** @todo Not exactly pretty to check strings; VBOXOSTYPE would be better, but that requires quite a bit of API change in Main. */
 
1070
            if (    fIOAPIC
 
1071
                &&  (   osTypeId == "WindowsNT4"
 
1072
                     || osTypeId == "Windows2000"
 
1073
                     || osTypeId == "WindowsXP"
 
1074
                     || osTypeId == "Windows2003"))
 
1075
            {
 
1076
                /* Only allow TPR patching for NT, Win2k, XP and Windows Server 2003. (32 bits mode)
 
1077
                 * We may want to consider adding more guest OSes (Solaris) later on.
 
1078
                 */
 
1079
                InsertConfigInteger(pHM, "TPRPatchingEnabled", 1);
 
1080
            }
 
1081
        }
 
1082
 
 
1083
        /* HWVirtEx exclusive mode */
 
1084
        BOOL fHMExclusive = true;
 
1085
        hrc = systemProperties->COMGETTER(ExclusiveHwVirt)(&fHMExclusive);                  H();
 
1086
        InsertConfigInteger(pHM, "Exclusive", fHMExclusive);
 
1087
 
 
1088
        /* Nested paging (VT-x/AMD-V) */
 
1089
        BOOL fEnableNestedPaging = false;
 
1090
        hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_NestedPaging, &fEnableNestedPaging); H();
 
1091
        InsertConfigInteger(pHM, "EnableNestedPaging", fEnableNestedPaging);
 
1092
 
 
1093
        /* Large pages; requires nested paging */
 
1094
        BOOL fEnableLargePages = false;
 
1095
        hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_LargePages, &fEnableLargePages); H();
 
1096
        InsertConfigInteger(pHM, "EnableLargePages", fEnableLargePages);
 
1097
 
 
1098
        /* VPID (VT-x) */
 
1099
        BOOL fEnableVPID = false;
 
1100
        hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_VPID, &fEnableVPID);       H();
 
1101
        InsertConfigInteger(pHM, "EnableVPID", fEnableVPID);
 
1102
 
 
1103
        /* Unrestricted execution aka UX (VT-x) */
 
1104
        BOOL fEnableUX = false;
 
1105
        hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_UnrestrictedExecution, &fEnableUX); H();
 
1106
        InsertConfigInteger(pHM, "EnableUX", fEnableUX);
 
1107
 
 
1108
        /* Reset overwrite. */
 
1109
        if (isResetTurnedIntoPowerOff())
 
1110
            InsertConfigInteger(pRoot, "PowerOffInsteadOfReset", 1);
 
1111
 
 
1112
 
 
1113
        /*
 
1114
         * MM values.
 
1115
         */
 
1116
        PCFGMNODE pMM;
 
1117
        InsertConfigNode(pRoot, "MM", &pMM);
 
1118
        InsertConfigInteger(pMM, "CanUseLargerHeap", chipsetType == ChipsetType_ICH9);
 
1119
 
 
1120
        /*
 
1121
         * PDM config.
 
1122
         *  Load drivers in VBoxC.[so|dll]
 
1123
         */
 
1124
        PCFGMNODE pPDM;
 
1125
        PCFGMNODE pNode;
 
1126
        PCFGMNODE pMod;
 
1127
        InsertConfigNode(pRoot,    "PDM", &pPDM);
 
1128
        InsertConfigNode(pPDM,     "Devices", &pNode);
 
1129
        InsertConfigNode(pPDM,     "Drivers", &pNode);
 
1130
        InsertConfigNode(pNode,    "VBoxC", &pMod);
 
1131
#ifdef VBOX_WITH_XPCOM
 
1132
        // VBoxC is located in the components subdirectory
 
1133
        char szPathVBoxC[RTPATH_MAX];
 
1134
        rc = RTPathAppPrivateArch(szPathVBoxC, RTPATH_MAX - sizeof("/components/VBoxC"));   AssertRC(rc);
 
1135
        strcat(szPathVBoxC, "/components/VBoxC");
 
1136
        InsertConfigString(pMod,   "Path",  szPathVBoxC);
 
1137
#else
 
1138
        InsertConfigString(pMod,   "Path",  "VBoxC");
 
1139
#endif
 
1140
 
 
1141
 
 
1142
        /*
 
1143
         * Block cache settings.
 
1144
         */
 
1145
        PCFGMNODE pPDMBlkCache;
 
1146
        InsertConfigNode(pPDM, "BlkCache", &pPDMBlkCache);
 
1147
 
 
1148
        /* I/O cache size */
 
1149
        ULONG ioCacheSize = 5;
 
1150
        hrc = pMachine->COMGETTER(IOCacheSize)(&ioCacheSize);                               H();
 
1151
        InsertConfigInteger(pPDMBlkCache, "CacheSize", ioCacheSize * _1M);
 
1152
 
 
1153
        /*
 
1154
         * Bandwidth groups.
 
1155
         */
 
1156
        PCFGMNODE pAc;
 
1157
        PCFGMNODE pAcFile;
 
1158
        PCFGMNODE pAcFileBwGroups;
 
1159
        ComPtr<IBandwidthControl> bwCtrl;
 
1160
        com::SafeIfaceArray<IBandwidthGroup> bwGroups;
 
1161
 
 
1162
        hrc = pMachine->COMGETTER(BandwidthControl)(bwCtrl.asOutParam());                   H();
 
1163
 
 
1164
        hrc = bwCtrl->GetAllBandwidthGroups(ComSafeArrayAsOutParam(bwGroups));              H();
 
1165
 
 
1166
        InsertConfigNode(pPDM, "AsyncCompletion", &pAc);
 
1167
        InsertConfigNode(pAc,  "File", &pAcFile);
 
1168
        InsertConfigNode(pAcFile,  "BwGroups", &pAcFileBwGroups);
 
1169
#ifdef VBOX_WITH_NETSHAPER
 
1170
        PCFGMNODE pNetworkShaper;
 
1171
        PCFGMNODE pNetworkBwGroups;
 
1172
 
 
1173
        InsertConfigNode(pPDM, "NetworkShaper",  &pNetworkShaper);
 
1174
        InsertConfigNode(pNetworkShaper, "BwGroups", &pNetworkBwGroups);
 
1175
#endif /* VBOX_WITH_NETSHAPER */
 
1176
 
 
1177
        for (size_t i = 0; i < bwGroups.size(); i++)
 
1178
        {
 
1179
            Bstr strName;
 
1180
            LONG64 cMaxBytesPerSec;
 
1181
            BandwidthGroupType_T enmType;
 
1182
 
 
1183
            hrc = bwGroups[i]->COMGETTER(Name)(strName.asOutParam());                       H();
 
1184
            hrc = bwGroups[i]->COMGETTER(Type)(&enmType);                                   H();
 
1185
            hrc = bwGroups[i]->COMGETTER(MaxBytesPerSec)(&cMaxBytesPerSec);                 H();
 
1186
 
 
1187
            if (strName.isEmpty())
 
1188
                return VMR3SetError(pUVM, VERR_CFGM_NO_NODE, RT_SRC_POS,
 
1189
                                    N_("No bandwidth group name specified"));
 
1190
 
 
1191
            if (enmType == BandwidthGroupType_Disk)
 
1192
            {
 
1193
                PCFGMNODE pBwGroup;
 
1194
                InsertConfigNode(pAcFileBwGroups, Utf8Str(strName).c_str(), &pBwGroup);
 
1195
                InsertConfigInteger(pBwGroup, "Max", cMaxBytesPerSec);
 
1196
                InsertConfigInteger(pBwGroup, "Start", cMaxBytesPerSec);
 
1197
                InsertConfigInteger(pBwGroup, "Step", 0);
 
1198
            }
 
1199
#ifdef VBOX_WITH_NETSHAPER
 
1200
            else if (enmType == BandwidthGroupType_Network)
 
1201
            {
 
1202
                /* Network bandwidth groups. */
 
1203
                PCFGMNODE pBwGroup;
 
1204
                InsertConfigNode(pNetworkBwGroups, Utf8Str(strName).c_str(), &pBwGroup);
 
1205
                InsertConfigInteger(pBwGroup, "Max", cMaxBytesPerSec);
 
1206
            }
 
1207
#endif /* VBOX_WITH_NETSHAPER */
 
1208
        }
 
1209
 
 
1210
        /*
 
1211
         * Devices
 
1212
         */
 
1213
        PCFGMNODE pDevices = NULL;      /* /Devices */
 
1214
        PCFGMNODE pDev = NULL;          /* /Devices/Dev/ */
 
1215
        PCFGMNODE pInst = NULL;         /* /Devices/Dev/0/ */
 
1216
        PCFGMNODE pCfg = NULL;          /* /Devices/Dev/.../Config/ */
 
1217
        PCFGMNODE pLunL0 = NULL;        /* /Devices/Dev/0/LUN#0/ */
 
1218
        PCFGMNODE pLunL1 = NULL;        /* /Devices/Dev/0/LUN#0/AttachedDriver/ */
 
1219
        PCFGMNODE pLunL2 = NULL;        /* /Devices/Dev/0/LUN#0/AttachedDriver/Config/ */
 
1220
        PCFGMNODE pBiosCfg = NULL;      /* /Devices/pcbios/0/Config/ */
 
1221
        PCFGMNODE pNetBootCfg = NULL;   /* /Devices/pcbios/0/Config/NetBoot/ */
 
1222
        bool fHaveBiosScsiConfig = false;
 
1223
 
 
1224
        InsertConfigNode(pRoot, "Devices", &pDevices);
 
1225
 
 
1226
        /*
 
1227
         * PC Arch.
 
1228
         */
 
1229
        InsertConfigNode(pDevices, "pcarch", &pDev);
 
1230
        InsertConfigNode(pDev,     "0", &pInst);
 
1231
        InsertConfigInteger(pInst, "Trusted",              1); /* boolean */
 
1232
        InsertConfigNode(pInst,    "Config", &pCfg);
 
1233
 
 
1234
        /*
 
1235
         * The time offset
 
1236
         */
 
1237
        LONG64 timeOffset;
 
1238
        hrc = biosSettings->COMGETTER(TimeOffset)(&timeOffset);                             H();
 
1239
        PCFGMNODE pTMNode;
 
1240
        InsertConfigNode(pRoot, "TM", &pTMNode);
 
1241
        InsertConfigInteger(pTMNode, "UTCOffset", timeOffset * 1000000);
 
1242
 
 
1243
        /*
 
1244
         * DMA
 
1245
         */
 
1246
        InsertConfigNode(pDevices, "8237A", &pDev);
 
1247
        InsertConfigNode(pDev,     "0", &pInst);
 
1248
        InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
 
1249
 
 
1250
        /*
 
1251
         * PCI buses.
 
1252
         */
 
1253
        uint32_t uIocPCIAddress, uHbcPCIAddress;
 
1254
        switch (chipsetType)
 
1255
        {
 
1256
            default:
 
1257
                Assert(false);
 
1258
            case ChipsetType_PIIX3:
 
1259
                InsertConfigNode(pDevices, "pci", &pDev);
 
1260
                uHbcPCIAddress = (0x0 << 16) | 0;
 
1261
                uIocPCIAddress = (0x1 << 16) | 0; // ISA controller
 
1262
                break;
 
1263
            case ChipsetType_ICH9:
 
1264
                InsertConfigNode(pDevices, "ich9pci", &pDev);
 
1265
                uHbcPCIAddress = (0x1e << 16) | 0;
 
1266
                uIocPCIAddress = (0x1f << 16) | 0; // LPC controller
 
1267
                break;
 
1268
        }
 
1269
        InsertConfigNode(pDev,     "0", &pInst);
 
1270
        InsertConfigInteger(pInst, "Trusted",              1); /* boolean */
 
1271
        InsertConfigNode(pInst,    "Config", &pCfg);
 
1272
        InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
 
1273
        if (chipsetType == ChipsetType_ICH9)
 
1274
        {
 
1275
            /* Provide MCFG info */
 
1276
            InsertConfigInteger(pCfg,  "McfgBase",   uMcfgBase);
 
1277
            InsertConfigInteger(pCfg,  "McfgLength", cbMcfgLength);
 
1278
 
 
1279
 
 
1280
            /* And register 2 bridges */
 
1281
            InsertConfigNode(pDevices, "ich9pcibridge", &pDev);
 
1282
            InsertConfigNode(pDev,     "0", &pInst);
 
1283
            InsertConfigInteger(pInst, "Trusted",              1); /* boolean */
 
1284
            hrc = pBusMgr->assignPCIDevice("ich9pcibridge", pInst);                         H();
 
1285
 
 
1286
            InsertConfigNode(pDev,     "1", &pInst);
 
1287
            InsertConfigInteger(pInst, "Trusted",              1); /* boolean */
 
1288
            hrc = pBusMgr->assignPCIDevice("ich9pcibridge", pInst);                         H();
 
1289
 
 
1290
#ifdef VBOX_WITH_PCI_PASSTHROUGH
 
1291
            /* Add PCI passthrough devices */
 
1292
            hrc = attachRawPCIDevices(pUVM, pBusMgr, pDevices);                             H();
 
1293
#endif
 
1294
        }
 
1295
 
 
1296
        /*
 
1297
         * Enable the following devices: HPET, SMC and LPC on MacOS X guests or on ICH9 chipset
 
1298
         */
 
1299
 
 
1300
        /*
 
1301
         * High Precision Event Timer (HPET)
 
1302
         */
 
1303
        BOOL fHPETEnabled;
 
1304
        /* Other guests may wish to use HPET too, but MacOS X not functional without it */
 
1305
        hrc = pMachine->COMGETTER(HPETEnabled)(&fHPETEnabled);                              H();
 
1306
        /* so always enable HPET in extended profile */
 
1307
        fHPETEnabled |= fOsXGuest;
 
1308
        /* HPET is always present on ICH9 */
 
1309
        fHPETEnabled |= (chipsetType == ChipsetType_ICH9);
 
1310
        if (fHPETEnabled)
 
1311
        {
 
1312
            InsertConfigNode(pDevices, "hpet", &pDev);
 
1313
            InsertConfigNode(pDev,     "0", &pInst);
 
1314
            InsertConfigInteger(pInst, "Trusted",   1); /* boolean */
 
1315
            InsertConfigNode(pInst,    "Config", &pCfg);
 
1316
            InsertConfigInteger(pCfg,  "ICH9", (chipsetType == ChipsetType_ICH9) ? 1 : 0);  /* boolean */
 
1317
        }
 
1318
 
 
1319
        /*
 
1320
         * System Management Controller (SMC)
 
1321
         */
 
1322
        BOOL fSmcEnabled;
 
1323
        fSmcEnabled = fOsXGuest;
 
1324
        if (fSmcEnabled)
 
1325
        {
 
1326
            InsertConfigNode(pDevices, "smc", &pDev);
 
1327
            InsertConfigNode(pDev,     "0", &pInst);
 
1328
            InsertConfigInteger(pInst, "Trusted",   1); /* boolean */
 
1329
            InsertConfigNode(pInst,    "Config", &pCfg);
 
1330
 
 
1331
            bool fGetKeyFromRealSMC;
 
1332
            Utf8Str strKey;
 
1333
            rc = getSmcDeviceKey(virtualBox, pMachine, &strKey, &fGetKeyFromRealSMC);
 
1334
            AssertRCReturn(rc, rc);
 
1335
 
 
1336
            if (!fGetKeyFromRealSMC)
 
1337
                InsertConfigString(pCfg,   "DeviceKey", strKey);
 
1338
            InsertConfigInteger(pCfg,  "GetKeyFromRealSMC", fGetKeyFromRealSMC);
 
1339
        }
 
1340
 
 
1341
        /*
 
1342
         * Low Pin Count (LPC) bus
 
1343
         */
 
1344
        BOOL fLpcEnabled;
 
1345
        /** @todo: implement appropriate getter */
 
1346
        fLpcEnabled = fOsXGuest || (chipsetType == ChipsetType_ICH9);
 
1347
        if (fLpcEnabled)
 
1348
        {
 
1349
            InsertConfigNode(pDevices, "lpc", &pDev);
 
1350
            InsertConfigNode(pDev,     "0", &pInst);
 
1351
            hrc = pBusMgr->assignPCIDevice("lpc", pInst);                                   H();
 
1352
            InsertConfigInteger(pInst, "Trusted",   1); /* boolean */
 
1353
        }
 
1354
 
 
1355
        BOOL fShowRtc;
 
1356
        fShowRtc = fOsXGuest || (chipsetType == ChipsetType_ICH9);
 
1357
 
 
1358
        /*
 
1359
         * PS/2 keyboard & mouse.
 
1360
         */
 
1361
        InsertConfigNode(pDevices, "pckbd", &pDev);
 
1362
        InsertConfigNode(pDev,     "0", &pInst);
 
1363
        InsertConfigInteger(pInst, "Trusted",              1); /* boolean */
 
1364
        InsertConfigNode(pInst,    "Config", &pCfg);
 
1365
 
 
1366
        InsertConfigNode(pInst,    "LUN#0", &pLunL0);
 
1367
        InsertConfigString(pLunL0, "Driver",               "KeyboardQueue");
 
1368
        InsertConfigNode(pLunL0,   "Config", &pCfg);
 
1369
        InsertConfigInteger(pCfg,  "QueueSize",            64);
 
1370
 
 
1371
        InsertConfigNode(pLunL0,   "AttachedDriver", &pLunL1);
 
1372
        InsertConfigString(pLunL1, "Driver",               "MainKeyboard");
 
1373
        InsertConfigNode(pLunL1,   "Config", &pCfg);
 
1374
        Keyboard *pKeyboard = mKeyboard;
 
1375
        InsertConfigInteger(pCfg,  "Object",     (uintptr_t)pKeyboard);
 
1376
 
 
1377
        Mouse *pMouse = mMouse;
 
1378
        PointingHIDType_T aPointingHID;
 
1379
        hrc = pMachine->COMGETTER(PointingHIDType)(&aPointingHID);                          H();
 
1380
        InsertConfigNode(pInst,    "LUN#1", &pLunL0);
 
1381
        InsertConfigString(pLunL0, "Driver",               "MouseQueue");
 
1382
        InsertConfigNode(pLunL0,   "Config", &pCfg);
 
1383
        InsertConfigInteger(pCfg, "QueueSize",            128);
 
1384
 
 
1385
        InsertConfigNode(pLunL0,   "AttachedDriver", &pLunL1);
 
1386
        InsertConfigString(pLunL1, "Driver",               "MainMouse");
 
1387
        InsertConfigNode(pLunL1,   "Config", &pCfg);
 
1388
        InsertConfigInteger(pCfg,  "Object",     (uintptr_t)pMouse);
 
1389
 
 
1390
        /*
 
1391
         * i8254 Programmable Interval Timer And Dummy Speaker
 
1392
         */
 
1393
        InsertConfigNode(pDevices, "i8254", &pDev);
 
1394
        InsertConfigNode(pDev,     "0", &pInst);
 
1395
        InsertConfigNode(pInst,    "Config", &pCfg);
 
1396
#ifdef DEBUG
 
1397
        InsertConfigInteger(pInst, "Trusted",              1); /* boolean */
 
1398
#endif
 
1399
 
 
1400
        /*
 
1401
         * i8259 Programmable Interrupt Controller.
 
1402
         */
 
1403
        InsertConfigNode(pDevices, "i8259", &pDev);
 
1404
        InsertConfigNode(pDev,     "0", &pInst);
 
1405
        InsertConfigInteger(pInst, "Trusted",              1); /* boolean */
 
1406
        InsertConfigNode(pInst,    "Config", &pCfg);
 
1407
 
 
1408
        /*
 
1409
         * Advanced Programmable Interrupt Controller.
 
1410
         * SMP: Each CPU has a LAPIC, but we have a single device representing all LAPICs states,
 
1411
         *      thus only single insert
 
1412
         */
 
1413
        InsertConfigNode(pDevices, "apic", &pDev);
 
1414
        InsertConfigNode(pDev, "0", &pInst);
 
1415
        InsertConfigInteger(pInst, "Trusted",              1); /* boolean */
 
1416
        InsertConfigNode(pInst,    "Config", &pCfg);
 
1417
        InsertConfigInteger(pCfg,  "IOAPIC", fIOAPIC);
 
1418
        InsertConfigInteger(pCfg,  "NumCPUs", cCpus);
 
1419
 
 
1420
        if (fIOAPIC)
 
1421
        {
 
1422
            /*
 
1423
             * I/O Advanced Programmable Interrupt Controller.
 
1424
             */
 
1425
            InsertConfigNode(pDevices, "ioapic", &pDev);
 
1426
            InsertConfigNode(pDev,     "0", &pInst);
 
1427
            InsertConfigInteger(pInst, "Trusted",          1); /* boolean */
 
1428
            InsertConfigNode(pInst,    "Config", &pCfg);
 
1429
            InsertConfigInteger(pCfg,  "NumCPUs", cCpus);
 
1430
        }
 
1431
 
 
1432
        /*
 
1433
         * RTC MC146818.
 
1434
         */
 
1435
        InsertConfigNode(pDevices, "mc146818", &pDev);
 
1436
        InsertConfigNode(pDev,     "0", &pInst);
 
1437
        InsertConfigNode(pInst,    "Config", &pCfg);
 
1438
        BOOL fRTCUseUTC;
 
1439
        hrc = pMachine->COMGETTER(RTCUseUTC)(&fRTCUseUTC);                                  H();
 
1440
        InsertConfigInteger(pCfg,  "UseUTC", fRTCUseUTC ? 1 : 0);
 
1441
 
 
1442
        /*
 
1443
         * VGA.
 
1444
         */
 
1445
        GraphicsControllerType_T enmGraphicsController;
 
1446
        hrc = pMachine->COMGETTER(GraphicsControllerType)(&enmGraphicsController);          H();
 
1447
        switch (enmGraphicsController)
 
1448
        {
 
1449
            case GraphicsControllerType_Null:
 
1450
                break;
 
1451
            case GraphicsControllerType_VBoxVGA:
 
1452
#ifdef VBOX_WITH_VMSVGA
 
1453
            case GraphicsControllerType_VMSVGA:
 
1454
#endif
 
1455
                rc = configGraphicsController(pDevices, enmGraphicsController, pBusMgr, pMachine, biosSettings,
 
1456
                                              RT_BOOL(fHMEnabled));
 
1457
                if (FAILED(rc))
 
1458
                    return rc;
 
1459
                break;
 
1460
            default:
 
1461
                AssertMsgFailed(("Invalid enmGraphicsController=%d\n", enmGraphicsController));
 
1462
                return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
 
1463
                                    N_("Invalid graphics controller type '%d'"), enmGraphicsController);
 
1464
        }
 
1465
 
 
1466
        /*
 
1467
         * Firmware.
 
1468
         */
 
1469
        FirmwareType_T eFwType =  FirmwareType_BIOS;
 
1470
        hrc = pMachine->COMGETTER(FirmwareType)(&eFwType);                                  H();
 
1471
 
 
1472
#ifdef VBOX_WITH_EFI
 
1473
        BOOL fEfiEnabled = (eFwType >= FirmwareType_EFI) && (eFwType <= FirmwareType_EFIDUAL);
 
1474
#else
 
1475
        BOOL fEfiEnabled = false;
 
1476
#endif
 
1477
        if (!fEfiEnabled)
 
1478
        {
 
1479
            /*
 
1480
             * PC Bios.
 
1481
             */
 
1482
            InsertConfigNode(pDevices, "pcbios", &pDev);
 
1483
            InsertConfigNode(pDev,     "0", &pInst);
 
1484
            InsertConfigInteger(pInst, "Trusted",              1); /* boolean */
 
1485
            InsertConfigNode(pInst,    "Config", &pBiosCfg);
 
1486
            InsertConfigInteger(pBiosCfg,  "RamSize",              cbRam);
 
1487
            InsertConfigInteger(pBiosCfg,  "RamHoleSize",          cbRamHole);
 
1488
            InsertConfigInteger(pBiosCfg,  "NumCPUs",              cCpus);
 
1489
            InsertConfigString(pBiosCfg,   "HardDiskDevice",       "piix3ide");
 
1490
            InsertConfigString(pBiosCfg,   "FloppyDevice",         "i82078");
 
1491
            InsertConfigInteger(pBiosCfg,  "IOAPIC",               fIOAPIC);
 
1492
            BOOL fPXEDebug;
 
1493
            hrc = biosSettings->COMGETTER(PXEDebugEnabled)(&fPXEDebug);                     H();
 
1494
            InsertConfigInteger(pBiosCfg,  "PXEDebug",             fPXEDebug);
 
1495
            InsertConfigBytes(pBiosCfg,    "UUID", &HardwareUuid,sizeof(HardwareUuid));
 
1496
            InsertConfigNode(pBiosCfg,     "NetBoot", &pNetBootCfg);
 
1497
            InsertConfigInteger(pBiosCfg,  "McfgBase",   uMcfgBase);
 
1498
            InsertConfigInteger(pBiosCfg,  "McfgLength", cbMcfgLength);
 
1499
 
 
1500
            DeviceType_T bootDevice;
 
1501
            AssertMsgReturn(SchemaDefs::MaxBootPosition <= 9, ("Too many boot devices %d\n", SchemaDefs::MaxBootPosition),
 
1502
                            VERR_INVALID_PARAMETER);
 
1503
 
 
1504
            for (ULONG pos = 1; pos <= SchemaDefs::MaxBootPosition; ++pos)
 
1505
            {
 
1506
                hrc = pMachine->GetBootOrder(pos, &bootDevice);                             H();
 
1507
 
 
1508
                char szParamName[] = "BootDeviceX";
 
1509
                szParamName[sizeof(szParamName) - 2] = ((char (pos - 1)) + '0');
 
1510
 
 
1511
                const char *pszBootDevice;
 
1512
                switch (bootDevice)
 
1513
                {
 
1514
                    case DeviceType_Null:
 
1515
                        pszBootDevice = "NONE";
 
1516
                        break;
 
1517
                    case DeviceType_HardDisk:
 
1518
                        pszBootDevice = "IDE";
 
1519
                        break;
 
1520
                    case DeviceType_DVD:
 
1521
                        pszBootDevice = "DVD";
 
1522
                        break;
 
1523
                    case DeviceType_Floppy:
 
1524
                        pszBootDevice = "FLOPPY";
 
1525
                        break;
 
1526
                    case DeviceType_Network:
 
1527
                        pszBootDevice = "LAN";
 
1528
                        break;
 
1529
                    default:
 
1530
                        AssertMsgFailed(("Invalid bootDevice=%d\n", bootDevice));
 
1531
                        return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
 
1532
                                            N_("Invalid boot device '%d'"), bootDevice);
 
1533
                }
 
1534
                InsertConfigString(pBiosCfg, szParamName, pszBootDevice);
 
1535
            }
 
1536
 
 
1537
            /** @todo @bugref{7145}: We might want to enable this by default for new VMs. For now,
 
1538
             *        this is required for Windows 2012 guests. */
 
1539
            if (osTypeId == "Windows2012_64")
 
1540
                InsertConfigInteger(pBiosCfg, "DmiExposeMemoryTable", 1); /* boolean */
 
1541
        }
 
1542
        else
 
1543
        {
 
1544
            /* Autodetect firmware type, basing on guest type */
 
1545
            if (eFwType == FirmwareType_EFI)
 
1546
            {
 
1547
                eFwType = fIsGuest64Bit
 
1548
                        ? (FirmwareType_T)FirmwareType_EFI64
 
1549
                        : (FirmwareType_T)FirmwareType_EFI32;
 
1550
            }
 
1551
            bool const f64BitEntry = eFwType == FirmwareType_EFI64;
 
1552
 
 
1553
            Utf8Str efiRomFile;
 
1554
            rc = findEfiRom(virtualBox, eFwType, &efiRomFile);
 
1555
            AssertRCReturn(rc, rc);
 
1556
 
 
1557
            /* Get boot args */
 
1558
            Utf8Str bootArgs;
 
1559
            GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiBootArgs", &bootArgs);
 
1560
 
 
1561
            /* Get device props */
 
1562
            Utf8Str deviceProps;
 
1563
            GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiDeviceProps", &deviceProps);
 
1564
 
 
1565
            /* Get GOP mode settings */
 
1566
            uint32_t u32GopMode = UINT32_MAX;
 
1567
            GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGopMode", &strTmp);
 
1568
            if (!strTmp.isEmpty())
 
1569
                u32GopMode = strTmp.toUInt32();
 
1570
 
 
1571
            /* UGA mode settings */
 
1572
            uint32_t u32UgaHorisontal = 0;
 
1573
            GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiUgaHorizontalResolution", &strTmp);
 
1574
            if (!strTmp.isEmpty())
 
1575
                u32UgaHorisontal = strTmp.toUInt32();
 
1576
 
 
1577
            uint32_t u32UgaVertical = 0;
 
1578
            GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiUgaVerticalResolution", &strTmp);
 
1579
            if (!strTmp.isEmpty())
 
1580
                u32UgaVertical = strTmp.toUInt32();
 
1581
 
 
1582
            /*
 
1583
             * EFI subtree.
 
1584
             */
 
1585
            InsertConfigNode(pDevices, "efi", &pDev);
 
1586
            InsertConfigNode(pDev,     "0", &pInst);
 
1587
            InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
 
1588
            InsertConfigNode(pInst,    "Config", &pCfg);
 
1589
            InsertConfigInteger(pCfg,  "RamSize",          cbRam);
 
1590
            InsertConfigInteger(pCfg,  "RamHoleSize",      cbRamHole);
 
1591
            InsertConfigInteger(pCfg,  "NumCPUs",          cCpus);
 
1592
            InsertConfigString(pCfg,   "EfiRom",           efiRomFile);
 
1593
            InsertConfigString(pCfg,   "BootArgs",         bootArgs);
 
1594
            InsertConfigString(pCfg,   "DeviceProps",      deviceProps);
 
1595
            InsertConfigInteger(pCfg,  "IOAPIC",           fIOAPIC);
 
1596
            InsertConfigBytes(pCfg,    "UUID", &HardwareUuid,sizeof(HardwareUuid));
 
1597
            InsertConfigInteger(pCfg,  "64BitEntry", f64BitEntry); /* boolean */
 
1598
            InsertConfigInteger(pCfg,  "GopMode", u32GopMode);
 
1599
            InsertConfigInteger(pCfg,  "UgaHorizontalResolution", u32UgaHorisontal);
 
1600
            InsertConfigInteger(pCfg,  "UgaVerticalResolution", u32UgaVertical);
 
1601
 
 
1602
            /* For OS X guests we'll force passing host's DMI info to the guest */
 
1603
            if (fOsXGuest)
 
1604
            {
 
1605
                InsertConfigInteger(pCfg, "DmiUseHostInfo", 1);
 
1606
                InsertConfigInteger(pCfg, "DmiExposeMemoryTable", 1);
 
1607
            }
 
1608
            InsertConfigNode(pInst,    "LUN#0", &pLunL0);
 
1609
            InsertConfigString(pLunL0, "Driver", "NvramStorage");
 
1610
            InsertConfigNode(pLunL0,   "Config", &pCfg);
 
1611
            InsertConfigInteger(pCfg,  "Object", (uintptr_t)mNvram);
 
1612
#ifdef DEBUG_vvl
 
1613
            InsertConfigInteger(pCfg,  "PermanentSave", 1);
 
1614
#endif
 
1615
        }
 
1616
 
 
1617
        /*
 
1618
         * Storage controllers.
 
1619
         */
 
1620
        com::SafeIfaceArray<IStorageController> ctrls;
 
1621
        PCFGMNODE aCtrlNodes[StorageControllerType_LsiLogicSas + 1] = {};
 
1622
        hrc = pMachine->COMGETTER(StorageControllers)(ComSafeArrayAsOutParam(ctrls));       H();
 
1623
 
 
1624
        bool fFdcEnabled = false;
 
1625
        for (size_t i = 0; i < ctrls.size(); ++i)
 
1626
        {
 
1627
            DeviceType_T *paLedDevType = NULL;
 
1628
 
 
1629
            StorageControllerType_T enmCtrlType;
 
1630
            rc = ctrls[i]->COMGETTER(ControllerType)(&enmCtrlType);                         H();
 
1631
            AssertRelease((unsigned)enmCtrlType < RT_ELEMENTS(aCtrlNodes));
 
1632
 
 
1633
            StorageBus_T enmBus;
 
1634
            rc = ctrls[i]->COMGETTER(Bus)(&enmBus);                                         H();
 
1635
 
 
1636
            Bstr controllerName;
 
1637
            rc = ctrls[i]->COMGETTER(Name)(controllerName.asOutParam());                    H();
 
1638
 
 
1639
            ULONG ulInstance = 999;
 
1640
            rc = ctrls[i]->COMGETTER(Instance)(&ulInstance);                                H();
 
1641
 
 
1642
            BOOL fUseHostIOCache;
 
1643
            rc = ctrls[i]->COMGETTER(UseHostIOCache)(&fUseHostIOCache);                     H();
 
1644
 
 
1645
            BOOL fBootable;
 
1646
            rc = ctrls[i]->COMGETTER(Bootable)(&fBootable);                                 H();
 
1647
 
 
1648
            /* /Devices/<ctrldev>/ */
 
1649
            const char *pszCtrlDev = convertControllerTypeToDev(enmCtrlType);
 
1650
            pDev = aCtrlNodes[enmCtrlType];
 
1651
            if (!pDev)
 
1652
            {
 
1653
                InsertConfigNode(pDevices, pszCtrlDev, &pDev);
 
1654
                aCtrlNodes[enmCtrlType] = pDev; /* IDE variants are handled in the switch */
 
1655
            }
 
1656
 
 
1657
            /* /Devices/<ctrldev>/<instance>/ */
 
1658
            PCFGMNODE pCtlInst = NULL;
 
1659
            InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pCtlInst);
 
1660
 
 
1661
            /* Device config: /Devices/<ctrldev>/<instance>/<values> & /ditto/Config/<values> */
 
1662
            InsertConfigInteger(pCtlInst, "Trusted",   1);
 
1663
            InsertConfigNode(pCtlInst,    "Config",    &pCfg);
 
1664
 
 
1665
            static const char * const apszBiosConfigScsi[MAX_BIOS_LUN_COUNT] =
 
1666
            { "ScsiLUN1", "ScsiLUN2", "ScsiLUN3", "ScsiLUN4" };
 
1667
 
 
1668
            static const char * const apszBiosConfigSata[MAX_BIOS_LUN_COUNT] =
 
1669
            { "SataLUN1", "SataLUN2", "SataLUN3", "SataLUN4" };
 
1670
 
 
1671
            switch (enmCtrlType)
 
1672
            {
 
1673
                case StorageControllerType_LsiLogic:
 
1674
                {
 
1675
                    hrc = pBusMgr->assignPCIDevice("lsilogic", pCtlInst);                   H();
 
1676
 
 
1677
                    InsertConfigInteger(pCfg, "Bootable",  fBootable);
 
1678
 
 
1679
                    /* BIOS configuration values, first controller only. */
 
1680
                    if (!pBusMgr->hasPCIDevice("lsilogicscsi", 1) && pBiosCfg)
 
1681
                    {
 
1682
                        if (!fHaveBiosScsiConfig)
 
1683
                        {
 
1684
                            fHaveBiosScsiConfig = true;
 
1685
                            InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "lsilogicscsi");
 
1686
 
 
1687
                            hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi);    H();
 
1688
                        }
 
1689
                    }
 
1690
 
 
1691
                    /* Attach the status driver */
 
1692
                    Assert(cLedScsi >= 16);
 
1693
                    attachStatusDriver(pCtlInst, &mapStorageLeds[iLedScsi], 0, 15,
 
1694
                                       &mapMediumAttachments, pszCtrlDev, ulInstance);
 
1695
                    paLedDevType = &maStorageDevType[iLedScsi];
 
1696
                    break;
 
1697
                }
 
1698
 
 
1699
                case StorageControllerType_BusLogic:
 
1700
                {
 
1701
                    hrc = pBusMgr->assignPCIDevice("buslogic", pCtlInst);                   H();
 
1702
 
 
1703
                    InsertConfigInteger(pCfg, "Bootable",  fBootable);
 
1704
 
 
1705
                    /* BIOS configuration values, first controller only. */
 
1706
                    if (!pBusMgr->hasPCIDevice("buslogic", 1) && pBiosCfg)
 
1707
                    {
 
1708
                        if (!fHaveBiosScsiConfig)
 
1709
                        {
 
1710
                            fHaveBiosScsiConfig = true;
 
1711
                            InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "buslogic");
 
1712
 
 
1713
                            hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi);    H();
 
1714
                        }
 
1715
                    }
 
1716
 
 
1717
                    /* Attach the status driver */
 
1718
                    Assert(cLedScsi >= 16);
 
1719
                    attachStatusDriver(pCtlInst, &mapStorageLeds[iLedScsi], 0, 15,
 
1720
                                       &mapMediumAttachments, pszCtrlDev, ulInstance);
 
1721
                    paLedDevType = &maStorageDevType[iLedScsi];
 
1722
                    break;
 
1723
                }
 
1724
 
 
1725
                case StorageControllerType_IntelAhci:
 
1726
                {
 
1727
                    hrc = pBusMgr->assignPCIDevice("ahci", pCtlInst);                       H();
 
1728
 
 
1729
                    ULONG cPorts = 0;
 
1730
                    hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts);                          H();
 
1731
                    InsertConfigInteger(pCfg, "PortCount", cPorts);
 
1732
                    InsertConfigInteger(pCfg, "Bootable",  fBootable);
 
1733
 
 
1734
                    /* Needed configuration values for the bios, only first controller. */
 
1735
                    if (!pBusMgr->hasPCIDevice("ahci", 1))
 
1736
                    {
 
1737
                        if (pBiosCfg)
 
1738
                        {
 
1739
                            InsertConfigString(pBiosCfg, "SataHardDiskDevice", "ahci");
 
1740
                        }
 
1741
 
 
1742
                        hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigSata);    H();
 
1743
                    }
 
1744
 
 
1745
                    GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/AhciPortsHotpluggable", &strTmp);
 
1746
                    if (!strTmp.isEmpty())
 
1747
                        InsertConfigInteger(pCfg, "PortsHotpluggable", strTmp == "1" ? true : false);
 
1748
 
 
1749
                    /* Attach the status driver */
 
1750
                    AssertRelease(cPorts <= cLedSata);
 
1751
                    attachStatusDriver(pCtlInst, &mapStorageLeds[iLedSata], 0, cPorts - 1,
 
1752
                                       &mapMediumAttachments, pszCtrlDev, ulInstance);
 
1753
                    paLedDevType = &maStorageDevType[iLedSata];
 
1754
                    break;
 
1755
                }
 
1756
 
 
1757
                case StorageControllerType_PIIX3:
 
1758
                case StorageControllerType_PIIX4:
 
1759
                case StorageControllerType_ICH6:
 
1760
                {
 
1761
                    /*
 
1762
                     * IDE (update this when the main interface changes)
 
1763
                     */
 
1764
                    hrc = pBusMgr->assignPCIDevice("piix3ide", pCtlInst);                   H();
 
1765
                    InsertConfigString(pCfg,   "Type", controllerString(enmCtrlType));
 
1766
                    /* Attach the status driver */
 
1767
                    Assert(cLedIde >= 4);
 
1768
                    attachStatusDriver(pCtlInst, &mapStorageLeds[iLedIde], 0, 3,
 
1769
                                       &mapMediumAttachments, pszCtrlDev, ulInstance);
 
1770
                    paLedDevType = &maStorageDevType[iLedIde];
 
1771
 
 
1772
                    /* IDE flavors */
 
1773
                    aCtrlNodes[StorageControllerType_PIIX3] = pDev;
 
1774
                    aCtrlNodes[StorageControllerType_PIIX4] = pDev;
 
1775
                    aCtrlNodes[StorageControllerType_ICH6]  = pDev;
 
1776
                    break;
 
1777
                }
 
1778
 
 
1779
                case StorageControllerType_I82078:
 
1780
                {
 
1781
                    /*
 
1782
                     * i82078 Floppy drive controller
 
1783
                     */
 
1784
                    fFdcEnabled = true;
 
1785
                    InsertConfigInteger(pCfg, "IRQ",       6);
 
1786
                    InsertConfigInteger(pCfg, "DMA",       2);
 
1787
                    InsertConfigInteger(pCfg, "MemMapped", 0 );
 
1788
                    InsertConfigInteger(pCfg, "IOBase",    0x3f0);
 
1789
 
 
1790
                    /* Attach the status driver */
 
1791
                    Assert(cLedFloppy >= 2);
 
1792
                    attachStatusDriver(pCtlInst, &mapStorageLeds[iLedFloppy], 0, 1,
 
1793
                                       &mapMediumAttachments, pszCtrlDev, ulInstance);
 
1794
                    paLedDevType = &maStorageDevType[iLedFloppy];
 
1795
                    break;
 
1796
                }
 
1797
 
 
1798
                case StorageControllerType_LsiLogicSas:
 
1799
                {
 
1800
                    hrc = pBusMgr->assignPCIDevice("lsilogicsas", pCtlInst);                H();
 
1801
 
 
1802
                    InsertConfigString(pCfg,  "ControllerType", "SAS1068");
 
1803
                    InsertConfigInteger(pCfg, "Bootable",  fBootable);
 
1804
 
 
1805
                    /* BIOS configuration values, first controller only. */
 
1806
                    if (!pBusMgr->hasPCIDevice("lsilogicsas", 1) && pBiosCfg)
 
1807
                    {
 
1808
                        if (!fHaveBiosScsiConfig)
 
1809
                        {
 
1810
                            fHaveBiosScsiConfig = true;
 
1811
                            InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "lsilogicsas");
 
1812
 
 
1813
                            hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi);    H();
 
1814
                        }
 
1815
                    }
 
1816
 
 
1817
                    ULONG cPorts = 0;
 
1818
                    hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts);                          H();
 
1819
                    InsertConfigInteger(pCfg, "NumPorts", cPorts);
 
1820
 
 
1821
                    /* Attach the status driver */
 
1822
                    Assert(cLedSas >= 8);
 
1823
                    attachStatusDriver(pCtlInst, &mapStorageLeds[iLedSas], 0, 7,
 
1824
                                       &mapMediumAttachments, pszCtrlDev, ulInstance);
 
1825
                    paLedDevType = &maStorageDevType[iLedSas];
 
1826
                    break;
 
1827
                }
 
1828
 
 
1829
                default:
 
1830
                    AssertLogRelMsgFailedReturn(("invalid storage controller type: %d\n", enmCtrlType), VERR_MAIN_CONFIG_CONSTRUCTOR_IPE);
 
1831
            }
 
1832
 
 
1833
            /* Attach the media to the storage controllers. */
 
1834
            com::SafeIfaceArray<IMediumAttachment> atts;
 
1835
            hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),
 
1836
                                                            ComSafeArrayAsOutParam(atts));  H();
 
1837
 
 
1838
            /* Builtin I/O cache - per device setting. */
 
1839
            BOOL fBuiltinIOCache = true;
 
1840
            hrc = pMachine->COMGETTER(IOCacheEnabled)(&fBuiltinIOCache);                    H();
 
1841
 
 
1842
 
 
1843
            for (size_t j = 0; j < atts.size(); ++j)
 
1844
            {
 
1845
                IMediumAttachment *pMediumAtt = atts[j];
 
1846
                rc = configMediumAttachment(pCtlInst,
 
1847
                                            pszCtrlDev,
 
1848
                                            ulInstance,
 
1849
                                            enmBus,
 
1850
                                            !!fUseHostIOCache,
 
1851
                                            !!fBuiltinIOCache,
 
1852
                                            false /* fSetupMerge */,
 
1853
                                            0 /* uMergeSource */,
 
1854
                                            0 /* uMergeTarget */,
 
1855
                                            pMediumAtt,
 
1856
                                            mMachineState,
 
1857
                                            NULL /* phrc */,
 
1858
                                            false /* fAttachDetach */,
 
1859
                                            false /* fForceUnmount */,
 
1860
                                            false /* fHotplug */,
 
1861
                                            pUVM,
 
1862
                                            paLedDevType,
 
1863
                                            NULL /* ppLunL0 */);
 
1864
                if (RT_FAILURE(rc))
 
1865
                    return rc;
 
1866
            }
 
1867
            H();
 
1868
        }
 
1869
        H();
 
1870
 
 
1871
        /*
 
1872
         * Network adapters
 
1873
         */
 
1874
#ifdef VMWARE_NET_IN_SLOT_11
 
1875
        bool fSwapSlots3and11 = false;
 
1876
#endif
 
1877
        PCFGMNODE pDevPCNet = NULL;          /* PCNet-type devices */
 
1878
        InsertConfigNode(pDevices, "pcnet", &pDevPCNet);
 
1879
#ifdef VBOX_WITH_E1000
 
1880
        PCFGMNODE pDevE1000 = NULL;          /* E1000-type devices */
 
1881
        InsertConfigNode(pDevices, "e1000", &pDevE1000);
 
1882
#endif
 
1883
#ifdef VBOX_WITH_VIRTIO
 
1884
        PCFGMNODE pDevVirtioNet = NULL;          /* Virtio network devices */
 
1885
        InsertConfigNode(pDevices, "virtio-net", &pDevVirtioNet);
 
1886
#endif /* VBOX_WITH_VIRTIO */
 
1887
        std::list<BootNic> llBootNics;
 
1888
        for (ULONG ulInstance = 0; ulInstance < maxNetworkAdapters; ++ulInstance)
 
1889
        {
 
1890
            ComPtr<INetworkAdapter> networkAdapter;
 
1891
            hrc = pMachine->GetNetworkAdapter(ulInstance, networkAdapter.asOutParam());     H();
 
1892
            BOOL fEnabledNetAdapter = FALSE;
 
1893
            hrc = networkAdapter->COMGETTER(Enabled)(&fEnabledNetAdapter);                  H();
 
1894
            if (!fEnabledNetAdapter)
 
1895
                continue;
 
1896
 
 
1897
            /*
 
1898
             * The virtual hardware type. Create appropriate device first.
 
1899
             */
 
1900
            const char *pszAdapterName = "pcnet";
 
1901
            NetworkAdapterType_T adapterType;
 
1902
            hrc = networkAdapter->COMGETTER(AdapterType)(&adapterType);                     H();
 
1903
            switch (adapterType)
 
1904
            {
 
1905
                case NetworkAdapterType_Am79C970A:
 
1906
                case NetworkAdapterType_Am79C973:
 
1907
                    pDev = pDevPCNet;
 
1908
                    break;
 
1909
#ifdef VBOX_WITH_E1000
 
1910
                case NetworkAdapterType_I82540EM:
 
1911
                case NetworkAdapterType_I82543GC:
 
1912
                case NetworkAdapterType_I82545EM:
 
1913
                    pDev = pDevE1000;
 
1914
                    pszAdapterName = "e1000";
 
1915
                    break;
 
1916
#endif
 
1917
#ifdef VBOX_WITH_VIRTIO
 
1918
                case NetworkAdapterType_Virtio:
 
1919
                    pDev = pDevVirtioNet;
 
1920
                    pszAdapterName = "virtio-net";
 
1921
                    break;
 
1922
#endif /* VBOX_WITH_VIRTIO */
 
1923
                default:
 
1924
                    AssertMsgFailed(("Invalid network adapter type '%d' for slot '%d'",
 
1925
                                    adapterType, ulInstance));
 
1926
                    return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
 
1927
                                        N_("Invalid network adapter type '%d' for slot '%d'"),
 
1928
                                        adapterType, ulInstance);
 
1929
            }
 
1930
 
 
1931
            InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
 
1932
            InsertConfigInteger(pInst, "Trusted",              1); /* boolean */
 
1933
            /* the first network card gets the PCI ID 3, the next 3 gets 8..10,
 
1934
             * next 4 get 16..19. */
 
1935
            int iPCIDeviceNo;
 
1936
            switch (ulInstance)
 
1937
            {
 
1938
                case 0:
 
1939
                    iPCIDeviceNo = 3;
 
1940
                    break;
 
1941
                case 1: case 2: case 3:
 
1942
                    iPCIDeviceNo = ulInstance - 1 + 8;
 
1943
                    break;
 
1944
                case 4: case 5: case 6: case 7:
 
1945
                    iPCIDeviceNo = ulInstance - 4 + 16;
 
1946
                    break;
 
1947
                default:
 
1948
                    /* auto assignment */
 
1949
                    iPCIDeviceNo = -1;
 
1950
                    break;
 
1951
            }
 
1952
#ifdef VMWARE_NET_IN_SLOT_11
 
1953
            /*
 
1954
             * Dirty hack for PCI slot compatibility with VMWare,
 
1955
             * it assigns slot 0x11 to the first network controller.
 
1956
             */
 
1957
            if (iPCIDeviceNo == 3 && adapterType == NetworkAdapterType_I82545EM)
 
1958
            {
 
1959
                iPCIDeviceNo = 0x11;
 
1960
                fSwapSlots3and11 = true;
 
1961
            }
 
1962
            else if (iPCIDeviceNo == 0x11 && fSwapSlots3and11)
 
1963
                iPCIDeviceNo = 3;
 
1964
#endif
 
1965
            PCIBusAddress PCIAddr = PCIBusAddress(0, iPCIDeviceNo, 0);
 
1966
            hrc = pBusMgr->assignPCIDevice(pszAdapterName, pInst, PCIAddr);                 H();
 
1967
 
 
1968
            InsertConfigNode(pInst, "Config", &pCfg);
 
1969
#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE   /* not safe here yet. */ /** @todo Make PCNet ring-0 safe on 32-bit mac kernels! */
 
1970
            if (pDev == pDevPCNet)
 
1971
            {
 
1972
                InsertConfigInteger(pCfg, "R0Enabled",    false);
 
1973
            }
 
1974
#endif
 
1975
            /*
 
1976
             * Collect information needed for network booting and add it to the list.
 
1977
             */
 
1978
            BootNic     nic;
 
1979
 
 
1980
            nic.mInstance    = ulInstance;
 
1981
            /* Could be updated by reference, if auto assigned */
 
1982
            nic.mPCIAddress  = PCIAddr;
 
1983
 
 
1984
            hrc = networkAdapter->COMGETTER(BootPriority)(&nic.mBootPrio);                  H();
 
1985
 
 
1986
            llBootNics.push_back(nic);
 
1987
 
 
1988
            /*
 
1989
             * The virtual hardware type. PCNet supports two types.
 
1990
             */
 
1991
            switch (adapterType)
 
1992
            {
 
1993
                case NetworkAdapterType_Am79C970A:
 
1994
                    InsertConfigInteger(pCfg, "Am79C973", 0);
 
1995
                    break;
 
1996
                case NetworkAdapterType_Am79C973:
 
1997
                    InsertConfigInteger(pCfg, "Am79C973", 1);
 
1998
                    break;
 
1999
                case NetworkAdapterType_I82540EM:
 
2000
                    InsertConfigInteger(pCfg, "AdapterType", 0);
 
2001
                    break;
 
2002
                case NetworkAdapterType_I82543GC:
 
2003
                    InsertConfigInteger(pCfg, "AdapterType", 1);
 
2004
                    break;
 
2005
                case NetworkAdapterType_I82545EM:
 
2006
                    InsertConfigInteger(pCfg, "AdapterType", 2);
 
2007
                    break;
 
2008
            }
 
2009
 
 
2010
            /*
 
2011
             * Get the MAC address and convert it to binary representation
 
2012
             */
 
2013
            Bstr macAddr;
 
2014
            hrc = networkAdapter->COMGETTER(MACAddress)(macAddr.asOutParam());              H();
 
2015
            Assert(!macAddr.isEmpty());
 
2016
            Utf8Str macAddrUtf8 = macAddr;
 
2017
            char *macStr = (char*)macAddrUtf8.c_str();
 
2018
            Assert(strlen(macStr) == 12);
 
2019
            RTMAC Mac;
 
2020
            RT_ZERO(Mac);
 
2021
            char *pMac = (char*)&Mac;
 
2022
            for (uint32_t i = 0; i < 6; ++i)
 
2023
            {
 
2024
                char c1 = *macStr++ - '0';
 
2025
                if (c1 > 9)
 
2026
                    c1 -= 7;
 
2027
                char c2 = *macStr++ - '0';
 
2028
                if (c2 > 9)
 
2029
                    c2 -= 7;
 
2030
                *pMac++ = ((c1 & 0x0f) << 4) | (c2 & 0x0f);
 
2031
            }
 
2032
            InsertConfigBytes(pCfg, "MAC", &Mac, sizeof(Mac));
 
2033
 
 
2034
            /*
 
2035
             * Check if the cable is supposed to be unplugged
 
2036
             */
 
2037
            BOOL fCableConnected;
 
2038
            hrc = networkAdapter->COMGETTER(CableConnected)(&fCableConnected);              H();
 
2039
            InsertConfigInteger(pCfg, "CableConnected", fCableConnected ? 1 : 0);
 
2040
 
 
2041
            /*
 
2042
             * Line speed to report from custom drivers
 
2043
             */
 
2044
            ULONG ulLineSpeed;
 
2045
            hrc = networkAdapter->COMGETTER(LineSpeed)(&ulLineSpeed);                       H();
 
2046
            InsertConfigInteger(pCfg, "LineSpeed", ulLineSpeed);
 
2047
 
 
2048
            /*
 
2049
             * Attach the status driver.
 
2050
             */
 
2051
            attachStatusDriver(pInst, &mapNetworkLeds[ulInstance], 0, 0, NULL, NULL, 0);
 
2052
 
 
2053
            /*
 
2054
             * Configure the network card now
 
2055
             */
 
2056
            bool fIgnoreConnectFailure = mMachineState == MachineState_Restoring;
 
2057
            rc = configNetwork(pszAdapterName,
 
2058
                               ulInstance,
 
2059
                               0,
 
2060
                               networkAdapter,
 
2061
                               pCfg,
 
2062
                               pLunL0,
 
2063
                               pInst,
 
2064
                               false /*fAttachDetach*/,
 
2065
                               fIgnoreConnectFailure);
 
2066
            if (RT_FAILURE(rc))
 
2067
                return rc;
 
2068
        }
 
2069
 
 
2070
        /*
 
2071
         * Build network boot information and transfer it to the BIOS.
 
2072
         */
 
2073
        if (pNetBootCfg && !llBootNics.empty())  /* NetBoot node doesn't exist for EFI! */
 
2074
        {
 
2075
            llBootNics.sort();  /* Sort the list by boot priority. */
 
2076
 
 
2077
            char        achBootIdx[] = "0";
 
2078
            unsigned    uBootIdx = 0;
 
2079
 
 
2080
            for (std::list<BootNic>::iterator it = llBootNics.begin(); it != llBootNics.end(); ++it)
 
2081
            {
 
2082
                /* A NIC with priority 0 is only used if it's first in the list. */
 
2083
                if (it->mBootPrio == 0 && uBootIdx != 0)
 
2084
                    break;
 
2085
 
 
2086
                PCFGMNODE pNetBtDevCfg;
 
2087
                achBootIdx[0] = '0' + uBootIdx++;   /* Boot device order. */
 
2088
                InsertConfigNode(pNetBootCfg, achBootIdx, &pNetBtDevCfg);
 
2089
                InsertConfigInteger(pNetBtDevCfg, "NIC", it->mInstance);
 
2090
                InsertConfigInteger(pNetBtDevCfg, "PCIBusNo",      it->mPCIAddress.miBus);
 
2091
                InsertConfigInteger(pNetBtDevCfg, "PCIDeviceNo",   it->mPCIAddress.miDevice);
 
2092
                InsertConfigInteger(pNetBtDevCfg, "PCIFunctionNo", it->mPCIAddress.miFn);
 
2093
            }
 
2094
        }
 
2095
 
 
2096
        /*
 
2097
         * Serial (UART) Ports
 
2098
         */
 
2099
        /* serial enabled mask to be passed to dev ACPI */
 
2100
        uint16_t auSerialIoPortBase[SchemaDefs::SerialPortCount] = {0};
 
2101
        uint8_t auSerialIrq[SchemaDefs::SerialPortCount] = {0};
 
2102
        InsertConfigNode(pDevices, "serial", &pDev);
 
2103
        for (ULONG ulInstance = 0; ulInstance < SchemaDefs::SerialPortCount; ++ulInstance)
 
2104
        {
 
2105
            ComPtr<ISerialPort> serialPort;
 
2106
            hrc = pMachine->GetSerialPort(ulInstance, serialPort.asOutParam());             H();
 
2107
            BOOL fEnabledSerPort = FALSE;
 
2108
            if (serialPort)
 
2109
                hrc = serialPort->COMGETTER(Enabled)(&fEnabledSerPort);                     H();
 
2110
            if (!fEnabledSerPort)
 
2111
                continue;
 
2112
 
 
2113
            InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
 
2114
            InsertConfigNode(pInst, "Config", &pCfg);
 
2115
 
 
2116
            ULONG ulIRQ;
 
2117
            hrc = serialPort->COMGETTER(IRQ)(&ulIRQ);                                       H();
 
2118
            InsertConfigInteger(pCfg, "IRQ", ulIRQ);
 
2119
            auSerialIrq[ulInstance] = (uint8_t)ulIRQ;
 
2120
 
 
2121
            ULONG ulIOBase;
 
2122
            hrc = serialPort->COMGETTER(IOBase)(&ulIOBase);                                 H();
 
2123
            InsertConfigInteger(pCfg, "IOBase", ulIOBase);
 
2124
            auSerialIoPortBase[ulInstance] = (uint16_t)ulIOBase;
 
2125
 
 
2126
            BOOL  fServer;
 
2127
            hrc = serialPort->COMGETTER(Server)(&fServer);                                  H();
 
2128
            hrc = serialPort->COMGETTER(Path)(bstr.asOutParam());                           H();
 
2129
            PortMode_T eHostMode;
 
2130
            hrc = serialPort->COMGETTER(HostMode)(&eHostMode);                              H();
 
2131
            if (eHostMode != PortMode_Disconnected)
 
2132
            {
 
2133
                InsertConfigNode(pInst,     "LUN#0", &pLunL0);
 
2134
                if (eHostMode == PortMode_HostPipe)
 
2135
                {
 
2136
                    InsertConfigString(pLunL0,  "Driver", "Char");
 
2137
                    InsertConfigNode(pLunL0,    "AttachedDriver", &pLunL1);
 
2138
                    InsertConfigString(pLunL1,  "Driver", "NamedPipe");
 
2139
                    InsertConfigNode(pLunL1,    "Config", &pLunL2);
 
2140
                    InsertConfigString(pLunL2,  "Location", bstr);
 
2141
                    InsertConfigInteger(pLunL2, "IsServer", fServer);
 
2142
                }
 
2143
                else if (eHostMode == PortMode_HostDevice)
 
2144
                {
 
2145
                    InsertConfigString(pLunL0,  "Driver", "Host Serial");
 
2146
                    InsertConfigNode(pLunL0,    "Config", &pLunL1);
 
2147
                    InsertConfigString(pLunL1,  "DevicePath", bstr);
 
2148
                }
 
2149
                else if (eHostMode == PortMode_RawFile)
 
2150
                {
 
2151
                    InsertConfigString(pLunL0,  "Driver", "Char");
 
2152
                    InsertConfigNode(pLunL0,    "AttachedDriver", &pLunL1);
 
2153
                    InsertConfigString(pLunL1,  "Driver", "RawFile");
 
2154
                    InsertConfigNode(pLunL1,    "Config", &pLunL2);
 
2155
                    InsertConfigString(pLunL2,  "Location", bstr);
 
2156
                }
 
2157
            }
 
2158
        }
 
2159
 
 
2160
        /*
 
2161
         * Parallel (LPT) Ports
 
2162
         */
 
2163
        InsertConfigNode(pDevices, "parallel", &pDev);
 
2164
        for (ULONG ulInstance = 0; ulInstance < SchemaDefs::ParallelPortCount; ++ulInstance)
 
2165
        {
 
2166
            ComPtr<IParallelPort> parallelPort;
 
2167
            hrc = pMachine->GetParallelPort(ulInstance, parallelPort.asOutParam());         H();
 
2168
            BOOL fEnabledParPort = FALSE;
 
2169
            if (parallelPort)
 
2170
            {
 
2171
                hrc = parallelPort->COMGETTER(Enabled)(&fEnabledParPort);                   H();
 
2172
            }
 
2173
            if (!fEnabledParPort)
 
2174
                continue;
 
2175
 
 
2176
            InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
 
2177
            InsertConfigNode(pInst, "Config", &pCfg);
 
2178
 
 
2179
            ULONG ulIRQ;
 
2180
            hrc = parallelPort->COMGETTER(IRQ)(&ulIRQ);                                     H();
 
2181
            InsertConfigInteger(pCfg, "IRQ", ulIRQ);
 
2182
            ULONG ulIOBase;
 
2183
            hrc = parallelPort->COMGETTER(IOBase)(&ulIOBase);                               H();
 
2184
            InsertConfigInteger(pCfg,   "IOBase", ulIOBase);
 
2185
            InsertConfigNode(pInst,     "LUN#0", &pLunL0);
 
2186
            InsertConfigString(pLunL0,  "Driver", "HostParallel");
 
2187
            InsertConfigNode(pLunL0,    "Config", &pLunL1);
 
2188
            hrc = parallelPort->COMGETTER(Path)(bstr.asOutParam());                         H();
 
2189
            InsertConfigString(pLunL1,  "DevicePath", bstr);
 
2190
        }
 
2191
 
 
2192
        /*
 
2193
         * VMM Device
 
2194
         */
 
2195
        InsertConfigNode(pDevices, "VMMDev", &pDev);
 
2196
        InsertConfigNode(pDev,     "0", &pInst);
 
2197
        InsertConfigNode(pInst,    "Config", &pCfg);
 
2198
        InsertConfigInteger(pInst, "Trusted",              1); /* boolean */
 
2199
        hrc = pBusMgr->assignPCIDevice("VMMDev", pInst);                                    H();
 
2200
 
 
2201
        Bstr hwVersion;
 
2202
        hrc = pMachine->COMGETTER(HardwareVersion)(hwVersion.asOutParam());                 H();
 
2203
        InsertConfigInteger(pCfg, "RamSize",              cbRam);
 
2204
        if (hwVersion.compare(Bstr("1").raw()) == 0) /* <= 2.0.x */
 
2205
            InsertConfigInteger(pCfg, "HeapEnabled", 0);
 
2206
        Bstr snapshotFolder;
 
2207
        hrc = pMachine->COMGETTER(SnapshotFolder)(snapshotFolder.asOutParam());             H();
 
2208
        InsertConfigString(pCfg, "GuestCoreDumpDir", snapshotFolder);
 
2209
 
 
2210
        /* the VMM device's Main driver */
 
2211
        InsertConfigNode(pInst,    "LUN#0", &pLunL0);
 
2212
        InsertConfigString(pLunL0, "Driver",               "HGCM");
 
2213
        InsertConfigNode(pLunL0,   "Config", &pCfg);
 
2214
        InsertConfigInteger(pCfg,  "Object", (uintptr_t)pVMMDev);
 
2215
 
 
2216
        /*
 
2217
         * Attach the status driver.
 
2218
         */
 
2219
        attachStatusDriver(pInst, &mapSharedFolderLed, 0, 0, NULL, NULL, 0);
 
2220
 
 
2221
        /*
 
2222
         * Audio Sniffer Device
 
2223
         */
 
2224
        InsertConfigNode(pDevices, "AudioSniffer", &pDev);
 
2225
        InsertConfigNode(pDev,     "0", &pInst);
 
2226
        InsertConfigNode(pInst,    "Config", &pCfg);
 
2227
 
 
2228
        /* the Audio Sniffer device's Main driver */
 
2229
        InsertConfigNode(pInst,    "LUN#0", &pLunL0);
 
2230
        InsertConfigString(pLunL0, "Driver",               "MainAudioSniffer");
 
2231
        InsertConfigNode(pLunL0,   "Config", &pCfg);
 
2232
        AudioSniffer *pAudioSniffer = mAudioSniffer;
 
2233
        InsertConfigInteger(pCfg,  "Object", (uintptr_t)pAudioSniffer);
 
2234
 
 
2235
        /*
 
2236
         * AC'97 ICH / SoundBlaster16 audio / Intel HD Audio
 
2237
         */
 
2238
        BOOL fAudioEnabled = FALSE;
 
2239
        ComPtr<IAudioAdapter> audioAdapter;
 
2240
        hrc = pMachine->COMGETTER(AudioAdapter)(audioAdapter.asOutParam());                 H();
 
2241
        if (audioAdapter)
 
2242
            hrc = audioAdapter->COMGETTER(Enabled)(&fAudioEnabled);                         H();
 
2243
 
 
2244
        if (fAudioEnabled)
 
2245
        {
 
2246
            AudioControllerType_T audioController;
 
2247
            hrc = audioAdapter->COMGETTER(AudioController)(&audioController);               H();
 
2248
            switch (audioController)
 
2249
            {
 
2250
                case AudioControllerType_AC97:
 
2251
                {
 
2252
                    /* default: ICH AC97 */
 
2253
                    InsertConfigNode(pDevices, "ichac97", &pDev);
 
2254
                    InsertConfigNode(pDev,     "0", &pInst);
 
2255
                    InsertConfigInteger(pInst, "Trusted",          1); /* boolean */
 
2256
                    hrc = pBusMgr->assignPCIDevice("ichac97", pInst);                       H();
 
2257
                    InsertConfigNode(pInst,    "Config", &pCfg);
 
2258
                    break;
 
2259
                }
 
2260
                case AudioControllerType_SB16:
 
2261
                {
 
2262
                    /* legacy SoundBlaster16 */
 
2263
                    InsertConfigNode(pDevices, "sb16", &pDev);
 
2264
                    InsertConfigNode(pDev,     "0", &pInst);
 
2265
                    InsertConfigInteger(pInst, "Trusted",          1); /* boolean */
 
2266
                    InsertConfigNode(pInst,    "Config", &pCfg);
 
2267
                    InsertConfigInteger(pCfg,  "IRQ", 5);
 
2268
                    InsertConfigInteger(pCfg,  "DMA", 1);
 
2269
                    InsertConfigInteger(pCfg,  "DMA16", 5);
 
2270
                    InsertConfigInteger(pCfg,  "Port", 0x220);
 
2271
                    InsertConfigInteger(pCfg,  "Version", 0x0405);
 
2272
                    break;
 
2273
                }
 
2274
                case AudioControllerType_HDA:
 
2275
                {
 
2276
                    /* Intel HD Audio */
 
2277
                    InsertConfigNode(pDevices, "hda", &pDev);
 
2278
                    InsertConfigNode(pDev,     "0", &pInst);
 
2279
                    InsertConfigInteger(pInst, "Trusted",          1); /* boolean */
 
2280
                    hrc = pBusMgr->assignPCIDevice("hda", pInst);                           H();
 
2281
                    InsertConfigNode(pInst,    "Config", &pCfg);
 
2282
                }
 
2283
            }
 
2284
 
 
2285
            /* the Audio driver */
 
2286
            InsertConfigNode(pInst,    "LUN#0", &pLunL0);
 
2287
            InsertConfigString(pLunL0, "Driver",               "AUDIO");
 
2288
            InsertConfigNode(pLunL0,   "Config", &pCfg);
 
2289
 
 
2290
            AudioDriverType_T audioDriver;
 
2291
            hrc = audioAdapter->COMGETTER(AudioDriver)(&audioDriver);                       H();
 
2292
            switch (audioDriver)
 
2293
            {
 
2294
                case AudioDriverType_Null:
 
2295
                {
 
2296
                    InsertConfigString(pCfg, "AudioDriver", "null");
 
2297
                    break;
 
2298
                }
 
2299
#ifdef RT_OS_WINDOWS
 
2300
#ifdef VBOX_WITH_WINMM
 
2301
                case AudioDriverType_WinMM:
 
2302
                {
 
2303
                    InsertConfigString(pCfg, "AudioDriver", "winmm");
 
2304
                    break;
 
2305
                }
 
2306
#endif
 
2307
                case AudioDriverType_DirectSound:
 
2308
                {
 
2309
                    InsertConfigString(pCfg, "AudioDriver", "dsound");
 
2310
                    break;
 
2311
                }
 
2312
#endif /* RT_OS_WINDOWS */
 
2313
#ifdef RT_OS_SOLARIS
 
2314
                case AudioDriverType_SolAudio:
 
2315
                {
 
2316
                    InsertConfigString(pCfg, "AudioDriver", "solaudio");
 
2317
                    break;
 
2318
                }
 
2319
#endif
 
2320
#ifdef RT_OS_LINUX
 
2321
# ifdef VBOX_WITH_ALSA
 
2322
                case AudioDriverType_ALSA:
 
2323
                {
 
2324
                    InsertConfigString(pCfg, "AudioDriver", "alsa");
 
2325
                    break;
 
2326
                }
 
2327
# endif
 
2328
# ifdef VBOX_WITH_PULSE
 
2329
                case AudioDriverType_Pulse:
 
2330
                {
 
2331
                    InsertConfigString(pCfg, "AudioDriver", "pulse");
 
2332
                    break;
 
2333
                }
 
2334
# endif
 
2335
#endif /* RT_OS_LINUX */
 
2336
#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD) || defined(VBOX_WITH_SOLARIS_OSS)
 
2337
                case AudioDriverType_OSS:
 
2338
                {
 
2339
                    InsertConfigString(pCfg, "AudioDriver", "oss");
 
2340
                    break;
 
2341
                }
 
2342
#endif
 
2343
#ifdef RT_OS_FREEBSD
 
2344
# ifdef VBOX_WITH_PULSE
 
2345
                case AudioDriverType_Pulse:
 
2346
                {
 
2347
                    InsertConfigString(pCfg, "AudioDriver", "pulse");
 
2348
                    break;
 
2349
                }
 
2350
# endif
 
2351
#endif
 
2352
#ifdef RT_OS_DARWIN
 
2353
                case AudioDriverType_CoreAudio:
 
2354
                {
 
2355
                    InsertConfigString(pCfg, "AudioDriver", "coreaudio");
 
2356
                    break;
 
2357
                }
 
2358
#endif
 
2359
            }
 
2360
            hrc = pMachine->COMGETTER(Name)(bstr.asOutParam());                             H();
 
2361
            InsertConfigString(pCfg, "StreamName", bstr);
 
2362
        }
 
2363
 
 
2364
        /*
 
2365
         * The USB Controllers.
 
2366
         */
 
2367
        com::SafeIfaceArray<IUSBController> usbCtrls;
 
2368
        hrc = pMachine->COMGETTER(USBControllers)(ComSafeArrayAsOutParam(usbCtrls));        H();
 
2369
        bool fOhciPresent = false; /**< Flag whether at least one OHCI controller is presnet. */
 
2370
 
 
2371
        for (size_t i = 0; i < usbCtrls.size(); ++i)
 
2372
        {
 
2373
            USBControllerType_T enmCtrlType;
 
2374
            rc = usbCtrls[i]->COMGETTER(Type)(&enmCtrlType);                                   H();
 
2375
            if (enmCtrlType == USBControllerType_OHCI)
 
2376
            {
 
2377
                fOhciPresent = true;
 
2378
                break;
 
2379
            }
 
2380
        }
 
2381
 
 
2382
        /*
 
2383
         * Currently EHCI is only enabled when a OHCI controller is present too.
 
2384
         * This might change when XHCI is supported.
 
2385
         */
 
2386
        if (fOhciPresent)
 
2387
            mfVMHasUsbController = true;
 
2388
 
 
2389
        if (mfVMHasUsbController)
 
2390
        {
 
2391
            for (size_t i = 0; i < usbCtrls.size(); ++i)
 
2392
            {
 
2393
                USBControllerType_T enmCtrlType;
 
2394
                rc = usbCtrls[i]->COMGETTER(Type)(&enmCtrlType);                                   H();
 
2395
 
 
2396
                if (enmCtrlType == USBControllerType_OHCI)
 
2397
                {
 
2398
                    InsertConfigNode(pDevices, "usb-ohci", &pDev);
 
2399
                    InsertConfigNode(pDev,     "0", &pInst);
 
2400
                    InsertConfigNode(pInst,    "Config", &pCfg);
 
2401
                    InsertConfigInteger(pInst, "Trusted",              1); /* boolean */
 
2402
                    hrc = pBusMgr->assignPCIDevice("usb-ohci", pInst);                          H();
 
2403
                    InsertConfigNode(pInst,    "LUN#0", &pLunL0);
 
2404
                    InsertConfigString(pLunL0, "Driver",               "VUSBRootHub");
 
2405
                    InsertConfigNode(pLunL0,   "Config", &pCfg);
 
2406
 
 
2407
                    /*
 
2408
                     * Attach the status driver.
 
2409
                     */
 
2410
                    attachStatusDriver(pInst, &mapUSBLed[0], 0, 0, NULL, NULL, 0);
 
2411
                }
 
2412
#ifdef VBOX_WITH_EHCI
 
2413
                else if (enmCtrlType == USBControllerType_EHCI)
 
2414
                {
 
2415
                    /*
 
2416
                     * USB 2.0 is only available if the proper ExtPack is installed.
 
2417
                     *
 
2418
                     * Note. Configuring EHCI here and providing messages about
 
2419
                     * the missing extpack isn't exactly clean, but it is a
 
2420
                     * necessary evil to patch over legacy compatability issues
 
2421
                     * introduced by the new distribution model.
 
2422
                     */
 
2423
                    static const char *s_pszUsbExtPackName = "Oracle VM VirtualBox Extension Pack";
 
2424
# ifdef VBOX_WITH_EXTPACK
 
2425
                    if (mptrExtPackManager->isExtPackUsable(s_pszUsbExtPackName))
 
2426
# endif
 
2427
                    {
 
2428
                        InsertConfigNode(pDevices, "usb-ehci", &pDev);
 
2429
                        InsertConfigNode(pDev,     "0", &pInst);
 
2430
                        InsertConfigNode(pInst,    "Config", &pCfg);
 
2431
                        InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
 
2432
                        hrc = pBusMgr->assignPCIDevice("usb-ehci", pInst);                  H();
 
2433
 
 
2434
                        InsertConfigNode(pInst,    "LUN#0", &pLunL0);
 
2435
                        InsertConfigString(pLunL0, "Driver",               "VUSBRootHub");
 
2436
                        InsertConfigNode(pLunL0,   "Config", &pCfg);
 
2437
 
 
2438
                        /*
 
2439
                         * Attach the status driver.
 
2440
                         */
 
2441
                        attachStatusDriver(pInst, &mapUSBLed[1], 0, 0, NULL, NULL, 0);
 
2442
                    }
 
2443
# ifdef VBOX_WITH_EXTPACK
 
2444
                    else
 
2445
                    {
 
2446
                        /* Always fatal! Up to VBox 4.0.4 we allowed to start the VM anyway
 
2447
                         * but this induced problems when the user saved + restored the VM! */
 
2448
                        return VMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
 
2449
                                N_("Implementation of the USB 2.0 controller not found!\n"
 
2450
                                   "Because the USB 2.0 controller state is part of the saved "
 
2451
                                   "VM state, the VM cannot be started. To fix "
 
2452
                                   "this problem, either install the '%s' or disable USB 2.0 "
 
2453
                                   "support in the VM settings.\n"
 
2454
                                   "Note! This error could also mean that an incompatible version of "
 
2455
                                   "the '%s' is installed"),
 
2456
                                s_pszUsbExtPackName, s_pszUsbExtPackName);
 
2457
                    }
 
2458
# endif
 
2459
                }
 
2460
#endif
 
2461
            } /* for every USB controller. */
 
2462
 
 
2463
 
 
2464
            /*
 
2465
             * Virtual USB Devices.
 
2466
             */
 
2467
            PCFGMNODE pUsbDevices = NULL;
 
2468
            InsertConfigNode(pRoot, "USB", &pUsbDevices);
 
2469
 
 
2470
#ifdef VBOX_WITH_USB
 
2471
            {
 
2472
                /*
 
2473
                 * Global USB options, currently unused as we'll apply the 2.0 -> 1.1 morphing
 
2474
                 * on a per device level now.
 
2475
                 */
 
2476
                InsertConfigNode(pUsbDevices, "USBProxy", &pCfg);
 
2477
                InsertConfigNode(pCfg, "GlobalConfig", &pCfg);
 
2478
                // This globally enables the 2.0 -> 1.1 device morphing of proxied devices to keep windows quiet.
 
2479
                //InsertConfigInteger(pCfg, "Force11Device", true);
 
2480
                // The following breaks stuff, but it makes MSDs work in vista. (I include it here so
 
2481
                // that it's documented somewhere.) Users needing it can use:
 
2482
                //      VBoxManage setextradata "myvm" "VBoxInternal/USB/USBProxy/GlobalConfig/Force11PacketSize" 1
 
2483
                //InsertConfigInteger(pCfg, "Force11PacketSize", true);
 
2484
            }
 
2485
#endif
 
2486
 
 
2487
#ifdef VBOX_WITH_USB_CARDREADER
 
2488
            BOOL aEmulatedUSBCardReaderEnabled = FALSE;
 
2489
            hrc = pMachine->COMGETTER(EmulatedUSBCardReaderEnabled)(&aEmulatedUSBCardReaderEnabled);    H();
 
2490
            if (aEmulatedUSBCardReaderEnabled)
 
2491
            {
 
2492
                InsertConfigNode(pUsbDevices, "CardReader", &pDev);
 
2493
                InsertConfigNode(pDev,     "0", &pInst);
 
2494
                InsertConfigNode(pInst,    "Config", &pCfg);
 
2495
 
 
2496
                InsertConfigNode(pInst,    "LUN#0", &pLunL0);
 
2497
# ifdef VBOX_WITH_USB_CARDREADER_TEST
 
2498
                InsertConfigString(pLunL0, "Driver", "DrvDirectCardReader");
 
2499
                InsertConfigNode(pLunL0,   "Config", &pCfg);
 
2500
# else
 
2501
                InsertConfigString(pLunL0, "Driver", "UsbCardReader");
 
2502
                InsertConfigNode(pLunL0,   "Config", &pCfg);
 
2503
                InsertConfigInteger(pCfg,  "Object", (uintptr_t)mUsbCardReader);
 
2504
# endif
 
2505
             }
 
2506
#endif
 
2507
 
 
2508
# if 0  /* Virtual MSD*/
 
2509
            InsertConfigNode(pUsbDevices, "Msd", &pDev);
 
2510
            InsertConfigNode(pDev,     "0", &pInst);
 
2511
            InsertConfigNode(pInst,    "Config", &pCfg);
 
2512
            InsertConfigNode(pInst,    "LUN#0", &pLunL0);
 
2513
 
 
2514
            InsertConfigString(pLunL0, "Driver", "SCSI");
 
2515
            InsertConfigNode(pLunL0,   "Config", &pCfg);
 
2516
 
 
2517
            InsertConfigNode(pLunL0,   "AttachedDriver", &pLunL1);
 
2518
            InsertConfigString(pLunL1, "Driver", "Block");
 
2519
            InsertConfigNode(pLunL1,   "Config", &pCfg);
 
2520
            InsertConfigString(pCfg,   "Type", "HardDisk");
 
2521
            InsertConfigInteger(pCfg,  "Mountable", 0);
 
2522
 
 
2523
            InsertConfigNode(pLunL1,   "AttachedDriver", &pLunL2);
 
2524
            InsertConfigString(pLunL2, "Driver", "VD");
 
2525
            InsertConfigNode(pLunL2,   "Config", &pCfg);
 
2526
            InsertConfigString(pCfg,   "Path", "/Volumes/DataHFS/bird/VDIs/linux.vdi");
 
2527
            InsertConfigString(pCfg,   "Format", "VDI");
 
2528
# endif
 
2529
 
 
2530
            /* Virtual USB Mouse/Tablet */
 
2531
            if (   aPointingHID == PointingHIDType_USBMouse
 
2532
                || aPointingHID == PointingHIDType_USBTablet
 
2533
                || aPointingHID == PointingHIDType_USBMultiTouch)
 
2534
            {
 
2535
                InsertConfigNode(pUsbDevices, "HidMouse", &pDev);
 
2536
                InsertConfigNode(pDev,     "0", &pInst);
 
2537
                InsertConfigNode(pInst,    "Config", &pCfg);
 
2538
 
 
2539
                if (aPointingHID == PointingHIDType_USBMouse)
 
2540
                    InsertConfigString(pCfg,   "Mode", "relative");
 
2541
                else
 
2542
                    InsertConfigString(pCfg,   "Mode", "absolute");
 
2543
                InsertConfigNode(pInst,    "LUN#0", &pLunL0);
 
2544
                InsertConfigString(pLunL0, "Driver",        "MouseQueue");
 
2545
                InsertConfigNode(pLunL0,   "Config", &pCfg);
 
2546
                InsertConfigInteger(pCfg,  "QueueSize",            128);
 
2547
 
 
2548
                InsertConfigNode(pLunL0,   "AttachedDriver", &pLunL1);
 
2549
                InsertConfigString(pLunL1, "Driver",        "MainMouse");
 
2550
                InsertConfigNode(pLunL1,   "Config", &pCfg);
 
2551
                InsertConfigInteger(pCfg,  "Object",     (uintptr_t)pMouse);
 
2552
            }
 
2553
            if (aPointingHID == PointingHIDType_USBMultiTouch)
 
2554
            {
 
2555
                InsertConfigNode(pDev,     "1", &pInst);
 
2556
                InsertConfigNode(pInst,    "Config", &pCfg);
 
2557
 
 
2558
                InsertConfigString(pCfg,   "Mode", "multitouch");
 
2559
                InsertConfigNode(pInst,    "LUN#0", &pLunL0);
 
2560
                InsertConfigString(pLunL0, "Driver",        "MouseQueue");
 
2561
                InsertConfigNode(pLunL0,   "Config", &pCfg);
 
2562
                InsertConfigInteger(pCfg,  "QueueSize",            128);
 
2563
 
 
2564
                InsertConfigNode(pLunL0,   "AttachedDriver", &pLunL1);
 
2565
                InsertConfigString(pLunL1, "Driver",        "MainMouse");
 
2566
                InsertConfigNode(pLunL1,   "Config", &pCfg);
 
2567
                InsertConfigInteger(pCfg,  "Object",     (uintptr_t)pMouse);
 
2568
            }
 
2569
 
 
2570
            /* Virtual USB Keyboard */
 
2571
            KeyboardHIDType_T aKbdHID;
 
2572
            hrc = pMachine->COMGETTER(KeyboardHIDType)(&aKbdHID);                       H();
 
2573
            if (aKbdHID == KeyboardHIDType_USBKeyboard)
 
2574
            {
 
2575
                InsertConfigNode(pUsbDevices, "HidKeyboard", &pDev);
 
2576
                InsertConfigNode(pDev,     "0", &pInst);
 
2577
                InsertConfigNode(pInst,    "Config", &pCfg);
 
2578
 
 
2579
                InsertConfigNode(pInst,    "LUN#0", &pLunL0);
 
2580
                InsertConfigString(pLunL0, "Driver",               "KeyboardQueue");
 
2581
                InsertConfigNode(pLunL0,   "Config", &pCfg);
 
2582
                InsertConfigInteger(pCfg,  "QueueSize",            64);
 
2583
 
 
2584
                InsertConfigNode(pLunL0,   "AttachedDriver", &pLunL1);
 
2585
                InsertConfigString(pLunL1, "Driver",               "MainKeyboard");
 
2586
                InsertConfigNode(pLunL1,   "Config", &pCfg);
 
2587
                pKeyboard = mKeyboard;
 
2588
                InsertConfigInteger(pCfg,  "Object",     (uintptr_t)pKeyboard);
 
2589
            }
 
2590
        }
 
2591
 
 
2592
        /*
 
2593
         * Clipboard
 
2594
         */
 
2595
        {
 
2596
            ClipboardMode_T mode = ClipboardMode_Disabled;
 
2597
            hrc = pMachine->COMGETTER(ClipboardMode)(&mode);                                H();
 
2598
 
 
2599
            if (/* mode != ClipboardMode_Disabled */ true)
 
2600
            {
 
2601
                /* Load the service */
 
2602
                rc = pVMMDev->hgcmLoadService("VBoxSharedClipboard", "VBoxSharedClipboard");
 
2603
 
 
2604
                if (RT_FAILURE(rc))
 
2605
                {
 
2606
                    LogRel(("VBoxSharedClipboard is not available. rc = %Rrc\n", rc));
 
2607
                    /* That is not a fatal failure. */
 
2608
                    rc = VINF_SUCCESS;
 
2609
                }
 
2610
                else
 
2611
                {
 
2612
                    changeClipboardMode(mode);
 
2613
 
 
2614
                    /* Setup the service. */
 
2615
                    VBOXHGCMSVCPARM parm;
 
2616
                    parm.type = VBOX_HGCM_SVC_PARM_32BIT;
 
2617
                    parm.setUInt32(!useHostClipboard());
 
2618
                    pVMMDev->hgcmHostCall("VBoxSharedClipboard", VBOX_SHARED_CLIPBOARD_HOST_FN_SET_HEADLESS, 1, &parm);
 
2619
 
 
2620
                    Log(("Set VBoxSharedClipboard mode\n"));
 
2621
                }
 
2622
            }
 
2623
        }
 
2624
 
 
2625
        /*
 
2626
         * HGCM HostChannel
 
2627
         */
 
2628
        {
 
2629
            Bstr value;
 
2630
            hrc = pMachine->GetExtraData(Bstr("HGCM/HostChannel").raw(),
 
2631
                                         value.asOutParam());
 
2632
 
 
2633
            if (   hrc   == S_OK
 
2634
                && value == "1")
 
2635
            {
 
2636
                rc = pVMMDev->hgcmLoadService("VBoxHostChannel", "VBoxHostChannel");
 
2637
 
 
2638
                if (RT_FAILURE(rc))
 
2639
                {
 
2640
                    LogRel(("VBoxHostChannel is not available. rc = %Rrc\n", rc));
 
2641
                    /* That is not a fatal failure. */
 
2642
                    rc = VINF_SUCCESS;
 
2643
                }
 
2644
            }
 
2645
        }
 
2646
 
 
2647
#ifdef VBOX_WITH_DRAG_AND_DROP
 
2648
        /*
 
2649
         * Drag & Drop
 
2650
         */
 
2651
        {
 
2652
            DragAndDropMode_T mode = DragAndDropMode_Disabled;
 
2653
            hrc = pMachine->COMGETTER(DragAndDropMode)(&mode);                              H();
 
2654
 
 
2655
            /* Load the service */
 
2656
            rc = pVMMDev->hgcmLoadService("VBoxDragAndDropSvc", "VBoxDragAndDropSvc");
 
2657
 
 
2658
            if (RT_FAILURE(rc))
 
2659
            {
 
2660
                LogRel(("VBoxDragAndDropService is not available. rc = %Rrc\n", rc));
 
2661
                /* That is not a fatal failure. */
 
2662
                rc = VINF_SUCCESS;
 
2663
            }
 
2664
            else
 
2665
            {
 
2666
                HGCMSVCEXTHANDLE hDummy;
 
2667
                rc = HGCMHostRegisterServiceExtension(&hDummy, "VBoxDragAndDropSvc",
 
2668
                                                      &GuestDnD::notifyGuestDragAndDropEvent,
 
2669
                                                      getGuest());
 
2670
                if (RT_FAILURE(rc))
 
2671
                    Log(("Cannot register VBoxDragAndDropSvc extension!\n"));
 
2672
                else
 
2673
                {
 
2674
                    changeDragAndDropMode(mode);
 
2675
                    Log(("VBoxDragAndDropSvc loaded\n"));
 
2676
                }
 
2677
            }
 
2678
        }
 
2679
#endif /* VBOX_WITH_DRAG_AND_DROP */
 
2680
 
 
2681
#ifdef VBOX_WITH_CROGL
 
2682
        /*
 
2683
         * crOpenGL
 
2684
         */
 
2685
        {
 
2686
            BOOL fEnabled3D = false;
 
2687
            hrc = pMachine->COMGETTER(Accelerate3DEnabled)(&fEnabled3D); H();
 
2688
 
 
2689
            if (   fEnabled3D
 
2690
# ifdef VBOX_WITH_VMSVGA3D
 
2691
                && enmGraphicsController == GraphicsControllerType_VBoxVGA
 
2692
# endif
 
2693
                )
 
2694
            {
 
2695
                BOOL fSupports3D = VBoxOglIs3DAccelerationSupported();
 
2696
                if (!fSupports3D)
 
2697
                    return VMR3SetError(pUVM, VERR_NOT_AVAILABLE, RT_SRC_POS,
 
2698
                            N_("This VM was configured to use 3D acceleration. However, the "
 
2699
                               "3D support of the host is not working properly and the "
 
2700
                               "VM cannot be started. To fix this problem, either "
 
2701
                               "fix the host 3D support (update the host graphics driver?) "
 
2702
                               "or disable 3D acceleration in the VM settings"));
 
2703
 
 
2704
                /* Load the service */
 
2705
                rc = pVMMDev->hgcmLoadService("VBoxSharedCrOpenGL", "VBoxSharedCrOpenGL");
 
2706
                if (RT_FAILURE(rc))
 
2707
                {
 
2708
                    LogRel(("Failed to load Shared OpenGL service %Rrc\n", rc));
 
2709
                    /* That is not a fatal failure. */
 
2710
                    rc = VINF_SUCCESS;
 
2711
                }
 
2712
                else
 
2713
                {
 
2714
                    LogRel(("Shared crOpenGL service loaded.\n"));
 
2715
 
 
2716
                    /* Setup the service. */
 
2717
                    VBOXHGCMSVCPARM parm;
 
2718
                    parm.type = VBOX_HGCM_SVC_PARM_PTR;
 
2719
 
 
2720
                    parm.u.pointer.addr = (IConsole *)(Console *)this;
 
2721
                    parm.u.pointer.size = sizeof(IConsole *);
 
2722
 
 
2723
                    rc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_SET_CONSOLE, SHCRGL_CPARMS_SET_CONSOLE, &parm);
 
2724
                    if (!RT_SUCCESS(rc))
 
2725
                        AssertMsgFailed(("SHCRGL_HOST_FN_SET_CONSOLE failed with %Rrc\n", rc));
 
2726
 
 
2727
                    parm.u.pointer.addr = pVM;
 
2728
                    parm.u.pointer.size = sizeof(pVM);
 
2729
                    rc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_SET_VM, SHCRGL_CPARMS_SET_VM, &parm);
 
2730
                    if (!RT_SUCCESS(rc))
 
2731
                        AssertMsgFailed(("SHCRGL_HOST_FN_SET_VM failed with %Rrc\n", rc));
 
2732
                }
 
2733
 
 
2734
            }
 
2735
        }
 
2736
#endif
 
2737
 
 
2738
#ifdef VBOX_WITH_GUEST_PROPS
 
2739
        /*
 
2740
         * Guest property service
 
2741
         */
 
2742
 
 
2743
        rc = configGuestProperties(this, pUVM);
 
2744
#endif /* VBOX_WITH_GUEST_PROPS defined */
 
2745
 
 
2746
#ifdef VBOX_WITH_GUEST_CONTROL
 
2747
        /*
 
2748
         * Guest control service
 
2749
         */
 
2750
 
 
2751
        rc = configGuestControl(this);
 
2752
#endif /* VBOX_WITH_GUEST_CONTROL defined */
 
2753
 
 
2754
        /*
 
2755
         * ACPI
 
2756
         */
 
2757
        BOOL fACPI;
 
2758
        hrc = biosSettings->COMGETTER(ACPIEnabled)(&fACPI);                                 H();
 
2759
        if (fACPI)
 
2760
        {
 
2761
            /* Always show the CPU leafs when we have multiple VCPUs or when the IO-APIC is enabled.
 
2762
             * The Windows SMP kernel needs a CPU leaf or else its idle loop will burn cpu cycles; the
 
2763
             * intelppm driver refuses to register an idle state handler.
 
2764
             * Always show CPU leafs for OS X guests. */
 
2765
            BOOL fShowCpu = fOsXGuest;
 
2766
            if (cCpus > 1 || fIOAPIC)
 
2767
                fShowCpu = true;
 
2768
 
 
2769
            BOOL fCpuHotPlug;
 
2770
            hrc = pMachine->COMGETTER(CPUHotPlugEnabled)(&fCpuHotPlug);                     H();
 
2771
 
 
2772
            InsertConfigNode(pDevices, "acpi", &pDev);
 
2773
            InsertConfigNode(pDev,     "0", &pInst);
 
2774
            InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
 
2775
            InsertConfigNode(pInst,    "Config", &pCfg);
 
2776
            hrc = pBusMgr->assignPCIDevice("acpi", pInst);                                  H();
 
2777
 
 
2778
            InsertConfigInteger(pCfg,  "RamSize",          cbRam);
 
2779
            InsertConfigInteger(pCfg,  "RamHoleSize",      cbRamHole);
 
2780
            InsertConfigInteger(pCfg,  "NumCPUs",          cCpus);
 
2781
 
 
2782
            InsertConfigInteger(pCfg,  "IOAPIC", fIOAPIC);
 
2783
            InsertConfigInteger(pCfg,  "FdcEnabled", fFdcEnabled);
 
2784
            InsertConfigInteger(pCfg,  "HpetEnabled", fHPETEnabled);
 
2785
            InsertConfigInteger(pCfg,  "SmcEnabled", fSmcEnabled);
 
2786
            InsertConfigInteger(pCfg,  "ShowRtc",    fShowRtc);
 
2787
            if (fOsXGuest && !llBootNics.empty())
 
2788
            {
 
2789
                BootNic aNic = llBootNics.front();
 
2790
                uint32_t u32NicPCIAddr = (aNic.mPCIAddress.miDevice << 16) | aNic.mPCIAddress.miFn;
 
2791
                InsertConfigInteger(pCfg, "NicPciAddress",    u32NicPCIAddr);
 
2792
            }
 
2793
            if (fOsXGuest && fAudioEnabled)
 
2794
            {
 
2795
                PCIBusAddress Address;
 
2796
                if (pBusMgr->findPCIAddress("hda", 0, Address))
 
2797
                {
 
2798
                    uint32_t u32AudioPCIAddr = (Address.miDevice << 16) | Address.miFn;
 
2799
                    InsertConfigInteger(pCfg, "AudioPciAddress",    u32AudioPCIAddr);
 
2800
                }
 
2801
            }
 
2802
            InsertConfigInteger(pCfg,  "IocPciAddress", uIocPCIAddress);
 
2803
            if (chipsetType == ChipsetType_ICH9)
 
2804
            {
 
2805
                InsertConfigInteger(pCfg,  "McfgBase",   uMcfgBase);
 
2806
                InsertConfigInteger(pCfg,  "McfgLength", cbMcfgLength);
 
2807
            }
 
2808
            InsertConfigInteger(pCfg,  "HostBusPciAddress", uHbcPCIAddress);
 
2809
            InsertConfigInteger(pCfg,  "ShowCpu", fShowCpu);
 
2810
            InsertConfigInteger(pCfg,  "CpuHotPlug", fCpuHotPlug);
 
2811
 
 
2812
            InsertConfigInteger(pCfg,  "Serial0IoPortBase", auSerialIoPortBase[0]);
 
2813
            InsertConfigInteger(pCfg,  "Serial0Irq", auSerialIrq[0]);
 
2814
 
 
2815
            InsertConfigInteger(pCfg,  "Serial1IoPortBase", auSerialIoPortBase[1]);
 
2816
            InsertConfigInteger(pCfg,  "Serial1Irq", auSerialIrq[1]);
 
2817
 
 
2818
            InsertConfigNode(pInst,    "LUN#0", &pLunL0);
 
2819
            InsertConfigString(pLunL0, "Driver",               "ACPIHost");
 
2820
            InsertConfigNode(pLunL0,   "Config", &pCfg);
 
2821
 
 
2822
            /* Attach the dummy CPU drivers */
 
2823
            for (ULONG iCpuCurr = 1; iCpuCurr < cCpus; iCpuCurr++)
 
2824
            {
 
2825
                BOOL fCpuAttached = true;
 
2826
 
 
2827
                if (fCpuHotPlug)
 
2828
                {
 
2829
                    hrc = pMachine->GetCPUStatus(iCpuCurr, &fCpuAttached);                  H();
 
2830
                }
 
2831
 
 
2832
                if (fCpuAttached)
 
2833
                {
 
2834
                    InsertConfigNode(pInst, Utf8StrFmt("LUN#%u", iCpuCurr).c_str(), &pLunL0);
 
2835
                    InsertConfigString(pLunL0, "Driver",           "ACPICpu");
 
2836
                    InsertConfigNode(pLunL0,   "Config", &pCfg);
 
2837
                }
 
2838
            }
 
2839
        }
 
2840
 
 
2841
        /*
 
2842
         * Configure DBGF (Debug(ger) Facility).
 
2843
         */
 
2844
        {
 
2845
            PCFGMNODE pDbgf;
 
2846
            InsertConfigNode(pRoot, "DBGF", &pDbgf);
 
2847
 
 
2848
            /* Paths to search for debug info and such things. */
 
2849
            hrc = pMachine->COMGETTER(SettingsFilePath)(bstr.asOutParam());                 H();
 
2850
            Utf8Str strSettingsPath(bstr);
 
2851
            bstr.setNull();
 
2852
            strSettingsPath.stripFilename();
 
2853
 
 
2854
            char szHomeDir[RTPATH_MAX];
 
2855
            rc = RTPathUserHome(szHomeDir, sizeof(szHomeDir));
 
2856
            if (RT_FAILURE(rc))
 
2857
                szHomeDir[0] = '\0';
 
2858
 
 
2859
            Utf8Str strPath;
 
2860
            strPath.append(strSettingsPath).append("/debug/;");
 
2861
            strPath.append(strSettingsPath).append("/;");
 
2862
            strPath.append(szHomeDir).append("/");
 
2863
 
 
2864
            InsertConfigString(pDbgf, "Path", strPath.c_str());
 
2865
 
 
2866
            /* Tracing configuration. */
 
2867
            BOOL fTracingEnabled;
 
2868
            hrc = pMachine->COMGETTER(TracingEnabled)(&fTracingEnabled);                    H();
 
2869
            if (fTracingEnabled)
 
2870
                InsertConfigInteger(pDbgf, "TracingEnabled", 1);
 
2871
 
 
2872
            hrc = pMachine->COMGETTER(TracingConfig)(bstr.asOutParam());                    H();
 
2873
            if (fTracingEnabled)
 
2874
                InsertConfigString(pDbgf, "TracingConfig", bstr);
 
2875
 
 
2876
            BOOL fAllowTracingToAccessVM;
 
2877
            hrc = pMachine->COMGETTER(AllowTracingToAccessVM)(&fAllowTracingToAccessVM);    H();
 
2878
            if (fAllowTracingToAccessVM)
 
2879
                InsertConfigInteger(pPDM, "AllowTracingToAccessVM", 1);
 
2880
        }
 
2881
    }
 
2882
    catch (ConfigError &x)
 
2883
    {
 
2884
        // InsertConfig threw something:
 
2885
        return x.m_vrc;
 
2886
    }
 
2887
    catch (HRESULT hrcXcpt)
 
2888
    {
 
2889
        AssertLogRelMsgFailedReturn(("hrc=%Rhrc\n", hrcXcpt), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
 
2890
    }
 
2891
 
 
2892
#ifdef VBOX_WITH_EXTPACK
 
2893
    /*
 
2894
     * Call the extension pack hooks if everything went well thus far.
 
2895
     */
 
2896
    if (RT_SUCCESS(rc))
 
2897
    {
 
2898
        pAlock->release();
 
2899
        rc = mptrExtPackManager->callAllVmConfigureVmmHooks(this, pVM);
 
2900
        pAlock->acquire();
 
2901
    }
 
2902
#endif
 
2903
 
 
2904
    /*
 
2905
     * Apply the CFGM overlay.
 
2906
     */
 
2907
    if (RT_SUCCESS(rc))
 
2908
        rc = configCfgmOverlay(pRoot, virtualBox, pMachine);
 
2909
 
 
2910
    /*
 
2911
     * Dump all extradata API settings tweaks, both global and per VM.
 
2912
     */
 
2913
    if (RT_SUCCESS(rc))
 
2914
        rc = configDumpAPISettingsTweaks(virtualBox, pMachine);
 
2915
 
 
2916
#undef H
 
2917
 
 
2918
    pAlock->release(); /* Avoid triggering the lock order inversion check. */
 
2919
 
 
2920
    /*
 
2921
     * Register VM state change handler.
 
2922
     */
 
2923
    int rc2 = VMR3AtStateRegister(pUVM, Console::vmstateChangeCallback, this);
 
2924
    AssertRC(rc2);
 
2925
    if (RT_SUCCESS(rc))
 
2926
        rc = rc2;
 
2927
 
 
2928
    /*
 
2929
     * Register VM runtime error handler.
 
2930
     */
 
2931
    rc2 = VMR3AtRuntimeErrorRegister(pUVM, Console::setVMRuntimeErrorCallback, this);
 
2932
    AssertRC(rc2);
 
2933
    if (RT_SUCCESS(rc))
 
2934
        rc = rc2;
 
2935
 
 
2936
    pAlock->acquire();
 
2937
 
 
2938
    LogFlowFunc(("vrc = %Rrc\n", rc));
 
2939
    LogFlowFuncLeave();
 
2940
 
 
2941
    return rc;
 
2942
}
 
2943
 
 
2944
/**
 
2945
 * Applies the CFGM overlay as specified by VBoxInternal/XXX extra data
 
2946
 * values.
 
2947
 *
 
2948
 * @returns VBox status code.
 
2949
 * @param   pRoot           The root of the configuration tree.
 
2950
 * @param   pVirtualBox     Pointer to the IVirtualBox interface.
 
2951
 * @param   pMachine        Pointer to the IMachine interface.
 
2952
 */
 
2953
/* static */
 
2954
int Console::configCfgmOverlay(PCFGMNODE pRoot, IVirtualBox *pVirtualBox, IMachine *pMachine)
 
2955
{
 
2956
    /*
 
2957
     * CFGM overlay handling.
 
2958
     *
 
2959
     * Here we check the extra data entries for CFGM values
 
2960
     * and create the nodes and insert the values on the fly. Existing
 
2961
     * values will be removed and reinserted. CFGM is typed, so by default
 
2962
     * we will guess whether it's a string or an integer (byte arrays are
 
2963
     * not currently supported). It's possible to override this autodetection
 
2964
     * by adding "string:", "integer:" or "bytes:" (future).
 
2965
     *
 
2966
     * We first perform a run on global extra data, then on the machine
 
2967
     * extra data to support global settings with local overrides.
 
2968
     */
 
2969
    int rc = VINF_SUCCESS;
 
2970
    try
 
2971
    {
 
2972
        /** @todo add support for removing nodes and byte blobs. */
 
2973
        /*
 
2974
         * Get the next key
 
2975
         */
 
2976
        SafeArray<BSTR> aGlobalExtraDataKeys;
 
2977
        SafeArray<BSTR> aMachineExtraDataKeys;
 
2978
        HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
 
2979
        AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
 
2980
 
 
2981
        // remember the no. of global values so we can call the correct method below
 
2982
        size_t cGlobalValues = aGlobalExtraDataKeys.size();
 
2983
 
 
2984
        hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
 
2985
        AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
 
2986
 
 
2987
        // build a combined list from global keys...
 
2988
        std::list<Utf8Str> llExtraDataKeys;
 
2989
 
 
2990
        for (size_t i = 0; i < aGlobalExtraDataKeys.size(); ++i)
 
2991
            llExtraDataKeys.push_back(Utf8Str(aGlobalExtraDataKeys[i]));
 
2992
        // ... and machine keys
 
2993
        for (size_t i = 0; i < aMachineExtraDataKeys.size(); ++i)
 
2994
            llExtraDataKeys.push_back(Utf8Str(aMachineExtraDataKeys[i]));
 
2995
 
 
2996
        size_t i2 = 0;
 
2997
        for (std::list<Utf8Str>::const_iterator it = llExtraDataKeys.begin();
 
2998
            it != llExtraDataKeys.end();
 
2999
            ++it, ++i2)
 
3000
        {
 
3001
            const Utf8Str &strKey = *it;
 
3002
 
 
3003
            /*
 
3004
             * We only care about keys starting with "VBoxInternal/" (skip "G:" or "M:")
 
3005
             */
 
3006
            if (!strKey.startsWith("VBoxInternal/"))
 
3007
                continue;
 
3008
 
 
3009
            const char *pszExtraDataKey = strKey.c_str() + sizeof("VBoxInternal/") - 1;
 
3010
 
 
3011
            // get the value
 
3012
            Bstr bstrExtraDataValue;
 
3013
            if (i2 < cGlobalValues)
 
3014
                // this is still one of the global values:
 
3015
                hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
 
3016
                                                bstrExtraDataValue.asOutParam());
 
3017
            else
 
3018
                hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
 
3019
                                             bstrExtraDataValue.asOutParam());
 
3020
            if (FAILED(hrc))
 
3021
                LogRel(("Warning: Cannot get extra data key %s, rc = %Rhrc\n", strKey.c_str(), hrc));
 
3022
 
 
3023
            /*
 
3024
             * The key will be in the format "Node1/Node2/Value" or simply "Value".
 
3025
             * Split the two and get the node, delete the value and create the node
 
3026
             * if necessary.
 
3027
             */
 
3028
            PCFGMNODE pNode;
 
3029
            const char *pszCFGMValueName = strrchr(pszExtraDataKey, '/');
 
3030
            if (pszCFGMValueName)
 
3031
            {
 
3032
                /* terminate the node and advance to the value (Utf8Str might not
 
3033
                offically like this but wtf) */
 
3034
                *(char*)pszCFGMValueName = '\0';
 
3035
                ++pszCFGMValueName;
 
3036
 
 
3037
                /* does the node already exist? */
 
3038
                pNode = CFGMR3GetChild(pRoot, pszExtraDataKey);
 
3039
                if (pNode)
 
3040
                    CFGMR3RemoveValue(pNode, pszCFGMValueName);
 
3041
                else
 
3042
                {
 
3043
                    /* create the node */
 
3044
                    rc = CFGMR3InsertNode(pRoot, pszExtraDataKey, &pNode);
 
3045
                    if (RT_FAILURE(rc))
 
3046
                    {
 
3047
                        AssertLogRelMsgRC(rc, ("failed to insert node '%s'\n", pszExtraDataKey));
 
3048
                        continue;
 
3049
                    }
 
3050
                    Assert(pNode);
 
3051
                }
 
3052
            }
 
3053
            else
 
3054
            {
 
3055
                /* root value (no node path). */
 
3056
                pNode = pRoot;
 
3057
                pszCFGMValueName = pszExtraDataKey;
 
3058
                pszExtraDataKey--;
 
3059
                CFGMR3RemoveValue(pNode, pszCFGMValueName);
 
3060
            }
 
3061
 
 
3062
            /*
 
3063
             * Now let's have a look at the value.
 
3064
             * Empty strings means that we should remove the value, which we've
 
3065
             * already done above.
 
3066
             */
 
3067
            Utf8Str strCFGMValueUtf8(bstrExtraDataValue);
 
3068
            if (!strCFGMValueUtf8.isEmpty())
 
3069
            {
 
3070
                uint64_t u64Value;
 
3071
 
 
3072
                /* check for type prefix first. */
 
3073
                if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("string:")))
 
3074
                    InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8.c_str() + sizeof("string:") - 1);
 
3075
                else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("integer:")))
 
3076
                {
 
3077
                    rc = RTStrToUInt64Full(strCFGMValueUtf8.c_str() + sizeof("integer:") - 1, 0, &u64Value);
 
3078
                    if (RT_SUCCESS(rc))
 
3079
                        rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
 
3080
                }
 
3081
                else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("bytes:")))
 
3082
                {
 
3083
                    char const *pszBase64 = strCFGMValueUtf8.c_str() + sizeof("bytes:") - 1;
 
3084
                    ssize_t cbValue = RTBase64DecodedSize(pszBase64, NULL);
 
3085
                    if (cbValue > 0)
 
3086
                    {
 
3087
                        void *pvBytes = RTMemTmpAlloc(cbValue);
 
3088
                        if (pvBytes)
 
3089
                        {
 
3090
                            rc = RTBase64Decode(pszBase64, pvBytes, cbValue, NULL, NULL);
 
3091
                            if (RT_SUCCESS(rc))
 
3092
                                rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, pvBytes, cbValue);
 
3093
                            RTMemTmpFree(pvBytes);
 
3094
                        }
 
3095
                        else
 
3096
                            rc = VERR_NO_TMP_MEMORY;
 
3097
                    }
 
3098
                    else if (cbValue == 0)
 
3099
                        rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, NULL, 0);
 
3100
                    else
 
3101
                        rc = VERR_INVALID_BASE64_ENCODING;
 
3102
                }
 
3103
                /* auto detect type. */
 
3104
                else if (RT_SUCCESS(RTStrToUInt64Full(strCFGMValueUtf8.c_str(), 0, &u64Value)))
 
3105
                    rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
 
3106
                else
 
3107
                    InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8);
 
3108
                AssertLogRelMsgRCBreak(rc, ("failed to insert CFGM value '%s' to key '%s'\n", strCFGMValueUtf8.c_str(), pszExtraDataKey));
 
3109
            }
 
3110
        }
 
3111
    }
 
3112
    catch (ConfigError &x)
 
3113
    {
 
3114
        // InsertConfig threw something:
 
3115
        return x.m_vrc;
 
3116
    }
 
3117
    return rc;
 
3118
}
 
3119
 
 
3120
/**
 
3121
 * Dumps the API settings tweaks as specified by VBoxInternal2/XXX extra data
 
3122
 * values.
 
3123
 *
 
3124
 * @returns VBox status code.
 
3125
 * @param   pVirtualBox     Pointer to the IVirtualBox interface.
 
3126
 * @param   pMachine        Pointer to the IMachine interface.
 
3127
 */
 
3128
/* static */
 
3129
int Console::configDumpAPISettingsTweaks(IVirtualBox *pVirtualBox, IMachine *pMachine)
 
3130
{
 
3131
    {
 
3132
        SafeArray<BSTR> aGlobalExtraDataKeys;
 
3133
        HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
 
3134
        AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
 
3135
        bool hasKey = false;
 
3136
        for (size_t i = 0; i < aGlobalExtraDataKeys.size(); i++)
 
3137
        {
 
3138
            Utf8Str strKey(aGlobalExtraDataKeys[i]);
 
3139
            if (!strKey.startsWith("VBoxInternal2/"))
 
3140
                continue;
 
3141
 
 
3142
            Bstr bstrValue;
 
3143
            hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
 
3144
                                            bstrValue.asOutParam());
 
3145
            if (FAILED(hrc))
 
3146
                continue;
 
3147
            if (!hasKey)
 
3148
                LogRel(("Global extradata API settings:\n"));
 
3149
            LogRel(("  %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
 
3150
            hasKey = true;
 
3151
        }
 
3152
    }
 
3153
 
 
3154
    {
 
3155
        SafeArray<BSTR> aMachineExtraDataKeys;
 
3156
        HRESULT hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
 
3157
        AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
 
3158
        bool hasKey = false;
 
3159
        for (size_t i = 0; i < aMachineExtraDataKeys.size(); i++)
 
3160
        {
 
3161
            Utf8Str strKey(aMachineExtraDataKeys[i]);
 
3162
            if (!strKey.startsWith("VBoxInternal2/"))
 
3163
                continue;
 
3164
 
 
3165
            Bstr bstrValue;
 
3166
            hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
 
3167
                                         bstrValue.asOutParam());
 
3168
            if (FAILED(hrc))
 
3169
                continue;
 
3170
            if (!hasKey)
 
3171
                LogRel(("Per-VM extradata API settings:\n"));
 
3172
            LogRel(("  %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
 
3173
            hasKey = true;
 
3174
        }
 
3175
    }
 
3176
 
 
3177
    return VINF_SUCCESS;
 
3178
}
 
3179
 
 
3180
int Console::configGraphicsController(PCFGMNODE pDevices,
 
3181
                                      const GraphicsControllerType_T enmGraphicsController,
 
3182
                                      BusAssignmentManager *pBusMgr,
 
3183
                                      const ComPtr<IMachine> &pMachine,
 
3184
                                      const ComPtr<IBIOSSettings> &biosSettings,
 
3185
                                      bool fHMEnabled)
 
3186
{
 
3187
    // InsertConfig* throws
 
3188
    try
 
3189
    {
 
3190
        PCFGMNODE pDev, pInst, pCfg, pLunL0;
 
3191
        HRESULT hrc;
 
3192
        Bstr    bstr;
 
3193
        const char *pcszDevice = "vga";
 
3194
 
 
3195
#define H()         AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
 
3196
        InsertConfigNode(pDevices, pcszDevice, &pDev);
 
3197
        InsertConfigNode(pDev,     "0", &pInst);
 
3198
        InsertConfigInteger(pInst, "Trusted",              1); /* boolean */
 
3199
 
 
3200
        hrc = pBusMgr->assignPCIDevice(pcszDevice, pInst);                                  H();
 
3201
        InsertConfigNode(pInst,    "Config", &pCfg);
 
3202
        ULONG cVRamMBs;
 
3203
        hrc = pMachine->COMGETTER(VRAMSize)(&cVRamMBs);                                     H();
 
3204
        InsertConfigInteger(pCfg,  "VRamSize",             cVRamMBs * _1M);
 
3205
        ULONG cMonitorCount;
 
3206
        hrc = pMachine->COMGETTER(MonitorCount)(&cMonitorCount);                            H();
 
3207
        InsertConfigInteger(pCfg,  "MonitorCount",         cMonitorCount);
 
3208
#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
 
3209
        InsertConfigInteger(pCfg,  "R0Enabled",            fHMEnabled);
 
3210
#else
 
3211
        NOREF(fHMEnabled);
 
3212
#endif
 
3213
 
 
3214
#ifdef VBOX_WITH_VMSVGA
 
3215
        if (enmGraphicsController == GraphicsControllerType_VMSVGA)
 
3216
        {
 
3217
            InsertConfigInteger(pCfg, "VMSVGAEnabled", true);
 
3218
#ifdef VBOX_WITH_VMSVGA3D
 
3219
            IFramebuffer *pFramebuffer = getDisplay()->getFramebuffer();
 
3220
            if (pFramebuffer)
 
3221
            {
 
3222
                LONG64 winId = 0;
 
3223
                /* @todo deal with multimonitor setup */
 
3224
                Assert(cMonitorCount == 1);
 
3225
                hrc = pFramebuffer->COMGETTER(WinId)(&winId);
 
3226
                InsertConfigInteger(pCfg, "HostWindowId", winId);
 
3227
            }
 
3228
            BOOL f3DEnabled;
 
3229
            pMachine->COMGETTER(Accelerate3DEnabled)(&f3DEnabled);
 
3230
            InsertConfigInteger(pCfg, "VMSVGA3dEnabled", f3DEnabled);
 
3231
#endif
 
3232
        }
 
3233
#endif
 
3234
 
 
3235
        /* Custom VESA mode list */
 
3236
        unsigned cModes = 0;
 
3237
        for (unsigned iMode = 1; iMode <= 16; ++iMode)
 
3238
        {
 
3239
            char szExtraDataKey[sizeof("CustomVideoModeXX")];
 
3240
            RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%u", iMode);
 
3241
            hrc = pMachine->GetExtraData(Bstr(szExtraDataKey).raw(), bstr.asOutParam());    H();
 
3242
            if (bstr.isEmpty())
 
3243
                break;
 
3244
            InsertConfigString(pCfg, szExtraDataKey, bstr);
 
3245
            ++cModes;
 
3246
        }
 
3247
        InsertConfigInteger(pCfg, "CustomVideoModes", cModes);
 
3248
 
 
3249
        /* VESA height reduction */
 
3250
        ULONG ulHeightReduction;
 
3251
        IFramebuffer *pFramebuffer = getDisplay()->getFramebuffer();
 
3252
        if (pFramebuffer)
 
3253
        {
 
3254
            hrc = pFramebuffer->COMGETTER(HeightReduction)(&ulHeightReduction);             H();
 
3255
        }
 
3256
        else
 
3257
        {
 
3258
            /* If framebuffer is not available, there is no height reduction. */
 
3259
            ulHeightReduction = 0;
 
3260
        }
 
3261
        InsertConfigInteger(pCfg,  "HeightReduction", ulHeightReduction);
 
3262
 
 
3263
        /*
 
3264
         * BIOS logo
 
3265
         */
 
3266
        BOOL fFadeIn;
 
3267
        hrc = biosSettings->COMGETTER(LogoFadeIn)(&fFadeIn);                                H();
 
3268
        InsertConfigInteger(pCfg,  "FadeIn",  fFadeIn ? 1 : 0);
 
3269
        BOOL fFadeOut;
 
3270
        hrc = biosSettings->COMGETTER(LogoFadeOut)(&fFadeOut);                              H();
 
3271
        InsertConfigInteger(pCfg,  "FadeOut", fFadeOut ? 1: 0);
 
3272
        ULONG logoDisplayTime;
 
3273
        hrc = biosSettings->COMGETTER(LogoDisplayTime)(&logoDisplayTime);                   H();
 
3274
        InsertConfigInteger(pCfg,  "LogoTime", logoDisplayTime);
 
3275
        Bstr logoImagePath;
 
3276
        hrc = biosSettings->COMGETTER(LogoImagePath)(logoImagePath.asOutParam());           H();
 
3277
        InsertConfigString(pCfg,   "LogoFile", Utf8Str(!logoImagePath.isEmpty() ? logoImagePath : "") );
 
3278
 
 
3279
        /*
 
3280
         * Boot menu
 
3281
         */
 
3282
        BIOSBootMenuMode_T eBootMenuMode;
 
3283
        int iShowBootMenu;
 
3284
        biosSettings->COMGETTER(BootMenuMode)(&eBootMenuMode);
 
3285
        switch (eBootMenuMode)
 
3286
        {
 
3287
            case BIOSBootMenuMode_Disabled: iShowBootMenu = 0;  break;
 
3288
            case BIOSBootMenuMode_MenuOnly: iShowBootMenu = 1;  break;
 
3289
            default:                        iShowBootMenu = 2;  break;
 
3290
        }
 
3291
        InsertConfigInteger(pCfg, "ShowBootMenu", iShowBootMenu);
 
3292
 
 
3293
        /* Attach the display. */
 
3294
        InsertConfigNode(pInst,    "LUN#0", &pLunL0);
 
3295
        InsertConfigString(pLunL0, "Driver",               "MainDisplay");
 
3296
        InsertConfigNode(pLunL0,   "Config", &pCfg);
 
3297
        Display *pDisplay = mDisplay;
 
3298
        InsertConfigInteger(pCfg,  "Object", (uintptr_t)pDisplay);
 
3299
    }
 
3300
    catch (ConfigError &x)
 
3301
    {
 
3302
        // InsertConfig threw something:
 
3303
        return x.m_vrc;
 
3304
    }
 
3305
 
 
3306
#undef H
 
3307
 
 
3308
    return VINF_SUCCESS;
 
3309
}
 
3310
 
 
3311
 
 
3312
/**
 
3313
 * Ellipsis to va_list wrapper for calling setVMRuntimeErrorCallback.
 
3314
 */
 
3315
void Console::setVMRuntimeErrorCallbackF(uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)
 
3316
{
 
3317
    va_list va;
 
3318
    va_start(va, pszFormat);
 
3319
    setVMRuntimeErrorCallback(NULL, this, fFlags, pszErrorId, pszFormat, va);
 
3320
    va_end(va);
 
3321
}
 
3322
 
 
3323
/* XXX introduce RT format specifier */
 
3324
static uint64_t formatDiskSize(uint64_t u64Size, const char **pszUnit)
 
3325
{
 
3326
    if (u64Size > INT64_C(5000)*_1G)
 
3327
    {
 
3328
        *pszUnit = "TB";
 
3329
        return u64Size / _1T;
 
3330
    }
 
3331
    else if (u64Size > INT64_C(5000)*_1M)
 
3332
    {
 
3333
        *pszUnit = "GB";
 
3334
        return u64Size / _1G;
 
3335
    }
 
3336
    else
 
3337
    {
 
3338
        *pszUnit = "MB";
 
3339
        return u64Size / _1M;
 
3340
    }
 
3341
}
 
3342
 
 
3343
int Console::configMediumAttachment(PCFGMNODE pCtlInst,
 
3344
                                    const char *pcszDevice,
 
3345
                                    unsigned uInstance,
 
3346
                                    StorageBus_T enmBus,
 
3347
                                    bool fUseHostIOCache,
 
3348
                                    bool fBuiltinIOCache,
 
3349
                                    bool fSetupMerge,
 
3350
                                    unsigned uMergeSource,
 
3351
                                    unsigned uMergeTarget,
 
3352
                                    IMediumAttachment *pMediumAtt,
 
3353
                                    MachineState_T aMachineState,
 
3354
                                    HRESULT *phrc,
 
3355
                                    bool fAttachDetach,
 
3356
                                    bool fForceUnmount,
 
3357
                                    bool fHotplug,
 
3358
                                    PUVM pUVM,
 
3359
                                    DeviceType_T *paLedDevType,
 
3360
                                    PCFGMNODE *ppLunL0)
 
3361
{
 
3362
    // InsertConfig* throws
 
3363
    try
 
3364
    {
 
3365
        int rc = VINF_SUCCESS;
 
3366
        HRESULT hrc;
 
3367
        Bstr    bstr;
 
3368
 
 
3369
// #define RC_CHECK()  AssertMsgReturn(RT_SUCCESS(rc), ("rc=%Rrc\n", rc), rc)
 
3370
#define H()         AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
 
3371
 
 
3372
        LONG lDev;
 
3373
        hrc = pMediumAtt->COMGETTER(Device)(&lDev);                                         H();
 
3374
        LONG lPort;
 
3375
        hrc = pMediumAtt->COMGETTER(Port)(&lPort);                                          H();
 
3376
        DeviceType_T lType;
 
3377
        hrc = pMediumAtt->COMGETTER(Type)(&lType);                                          H();
 
3378
        BOOL fNonRotational;
 
3379
        hrc = pMediumAtt->COMGETTER(NonRotational)(&fNonRotational);                        H();
 
3380
        BOOL fDiscard;
 
3381
        hrc = pMediumAtt->COMGETTER(Discard)(&fDiscard);                                    H();
 
3382
 
 
3383
        unsigned uLUN;
 
3384
        PCFGMNODE pLunL0 = NULL;
 
3385
        hrc = Console::convertBusPortDeviceToLun(enmBus, lPort, lDev, uLUN);                H();
 
3386
 
 
3387
        /* First check if the LUN already exists. */
 
3388
        pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
 
3389
        if (pLunL0)
 
3390
        {
 
3391
            if (fAttachDetach)
 
3392
            {
 
3393
                if (lType != DeviceType_HardDisk)
 
3394
                {
 
3395
                    /* Unmount existing media only for floppy and DVD drives. */
 
3396
                    PPDMIBASE pBase;
 
3397
                    rc = PDMR3QueryLun(pUVM, pcszDevice, uInstance, uLUN, &pBase);
 
3398
                    if (RT_FAILURE(rc))
 
3399
                    {
 
3400
                        if (rc == VERR_PDM_LUN_NOT_FOUND || rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
 
3401
                            rc = VINF_SUCCESS;
 
3402
                        AssertRC(rc);
 
3403
                    }
 
3404
                    else
 
3405
                    {
 
3406
                        PPDMIMOUNT pIMount = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMOUNT);
 
3407
                        AssertReturn(pIMount, VERR_INVALID_POINTER);
 
3408
 
 
3409
                        /* Unmount the media (but do not eject the medium!) */
 
3410
                        rc = pIMount->pfnUnmount(pIMount, fForceUnmount, false /*=fEject*/);
 
3411
                        if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
 
3412
                            rc = VINF_SUCCESS;
 
3413
                        /* for example if the medium is locked */
 
3414
                        else if (RT_FAILURE(rc))
 
3415
                            return rc;
 
3416
                    }
 
3417
                }
 
3418
 
 
3419
                rc = PDMR3DeviceDetach(pUVM, pcszDevice, uInstance, uLUN, fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
 
3420
                if (rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
 
3421
                    rc = VINF_SUCCESS;
 
3422
                AssertRCReturn(rc, rc);
 
3423
 
 
3424
                CFGMR3RemoveNode(pLunL0);
 
3425
            }
 
3426
            else
 
3427
                AssertFailedReturn(VERR_INTERNAL_ERROR);
 
3428
        }
 
3429
 
 
3430
        InsertConfigNode(pCtlInst, Utf8StrFmt("LUN#%u", uLUN).c_str(), &pLunL0);
 
3431
        if (ppLunL0)
 
3432
            *ppLunL0 = pLunL0;
 
3433
 
 
3434
        PCFGMNODE pCfg = CFGMR3GetChild(pCtlInst, "Config");
 
3435
        if (pCfg)
 
3436
        {
 
3437
            if (!strcmp(pcszDevice, "piix3ide"))
 
3438
            {
 
3439
                PCFGMNODE pDrive = CFGMR3GetChild(pCfg, g_apszIDEDrives[uLUN]);
 
3440
                if (!pDrive)
 
3441
                    InsertConfigNode(pCfg, g_apszIDEDrives[uLUN], &pDrive);
 
3442
                /* Don't use the RemoveConfigValue wrapper above, as we don't
 
3443
                 * know if the leaf is present or not. */
 
3444
                CFGMR3RemoveValue(pDrive,  "NonRotationalMedium");
 
3445
                InsertConfigInteger(pDrive, "NonRotationalMedium", !!fNonRotational);
 
3446
            }
 
3447
            else if (!strcmp(pcszDevice, "ahci"))
 
3448
            {
 
3449
                Utf8Str strPort = Utf8StrFmt("Port%u", uLUN);
 
3450
                PCFGMNODE pDrive = CFGMR3GetChild(pCfg, strPort.c_str());
 
3451
                if (!pDrive)
 
3452
                    InsertConfigNode(pCfg, strPort.c_str(), &pDrive);
 
3453
                /* Don't use the RemoveConfigValue wrapper above, as we don't
 
3454
                 * know if the leaf is present or not. */
 
3455
                CFGMR3RemoveValue(pDrive,  "NonRotationalMedium");
 
3456
                InsertConfigInteger(pDrive, "NonRotationalMedium", !!fNonRotational);
 
3457
            }
 
3458
        }
 
3459
 
 
3460
        Utf8Str devicePath = Utf8StrFmt("%s/%u/LUN#%u", pcszDevice, uInstance, uLUN);
 
3461
        mapMediumAttachments[devicePath] = pMediumAtt;
 
3462
 
 
3463
        /* SCSI has a another driver between device and block. */
 
3464
        if (enmBus == StorageBus_SCSI || enmBus == StorageBus_SAS)
 
3465
        {
 
3466
            InsertConfigString(pLunL0, "Driver", "SCSI");
 
3467
            PCFGMNODE pL1Cfg = NULL;
 
3468
            InsertConfigNode(pLunL0, "Config", &pL1Cfg);
 
3469
            InsertConfigInteger(pL1Cfg, "NonRotationalMedium", !!fNonRotational);
 
3470
 
 
3471
            InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
 
3472
        }
 
3473
 
 
3474
        ComPtr<IMedium> pMedium;
 
3475
        hrc = pMediumAtt->COMGETTER(Medium)(pMedium.asOutParam());                          H();
 
3476
 
 
3477
        /*
 
3478
         * 1. Only check this for hard disk images.
 
3479
         * 2. Only check during VM creation and not later, especially not during
 
3480
         *    taking an online snapshot!
 
3481
         */
 
3482
        if (   lType == DeviceType_HardDisk
 
3483
            && (   aMachineState == MachineState_Starting
 
3484
                || aMachineState == MachineState_Restoring))
 
3485
        {
 
3486
            /*
 
3487
             * Some sanity checks.
 
3488
             */
 
3489
            ComPtr<IMediumFormat> pMediumFormat;
 
3490
            hrc = pMedium->COMGETTER(MediumFormat)(pMediumFormat.asOutParam());             H();
 
3491
            ULONG uCaps = 0;
 
3492
            com::SafeArray <MediumFormatCapabilities_T> mediumFormatCap;
 
3493
            hrc = pMediumFormat->COMGETTER(Capabilities)(ComSafeArrayAsOutParam(mediumFormatCap));    H();
 
3494
 
 
3495
            for (ULONG j = 0; j < mediumFormatCap.size(); j++)
 
3496
                uCaps |= mediumFormatCap[j];
 
3497
 
 
3498
            if (uCaps & MediumFormatCapabilities_File)
 
3499
            {
 
3500
                Bstr strFile;
 
3501
                hrc = pMedium->COMGETTER(Location)(strFile.asOutParam());                   H();
 
3502
                Utf8Str utfFile = Utf8Str(strFile);
 
3503
                Bstr strSnap;
 
3504
                ComPtr<IMachine> pMachine = machine();
 
3505
                hrc = pMachine->COMGETTER(SnapshotFolder)(strSnap.asOutParam());            H();
 
3506
                Utf8Str utfSnap = Utf8Str(strSnap);
 
3507
                RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
 
3508
                RTFSTYPE enmFsTypeSnap = RTFSTYPE_UNKNOWN;
 
3509
                int rc2 = RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
 
3510
                AssertMsgRCReturn(rc2, ("Querying the file type of '%s' failed!\n", utfFile.c_str()), rc2);
 
3511
                /* Ignore the error code. On error, the file system type is still 'unknown' so
 
3512
                 * none of the following paths are taken. This can happen for new VMs which
 
3513
                 * still don't have a snapshot folder. */
 
3514
                (void)RTFsQueryType(utfSnap.c_str(), &enmFsTypeSnap);
 
3515
                if (!mfSnapshotFolderDiskTypeShown)
 
3516
                {
 
3517
                    LogRel(("File system of '%s' (snapshots) is %s\n",
 
3518
                            utfSnap.c_str(), RTFsTypeName(enmFsTypeSnap)));
 
3519
                    mfSnapshotFolderDiskTypeShown = true;
 
3520
                }
 
3521
                LogRel(("File system of '%s' is %s\n", utfFile.c_str(), RTFsTypeName(enmFsTypeFile)));
 
3522
                LONG64 i64Size;
 
3523
                hrc = pMedium->COMGETTER(LogicalSize)(&i64Size);                            H();
 
3524
#ifdef RT_OS_WINDOWS
 
3525
                if (   enmFsTypeFile == RTFSTYPE_FAT
 
3526
                    && i64Size >= _4G)
 
3527
                {
 
3528
                    const char *pszUnit;
 
3529
                    uint64_t u64Print = formatDiskSize((uint64_t)i64Size, &pszUnit);
 
3530
                    setVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
 
3531
                            N_("The medium '%ls' has a logical size of %RU64%s "
 
3532
                            "but the file system the medium is located on seems "
 
3533
                            "to be FAT(32) which cannot handle files bigger than 4GB.\n"
 
3534
                            "We strongly recommend to put all your virtual disk images and "
 
3535
                            "the snapshot folder onto an NTFS partition"),
 
3536
                            strFile.raw(), u64Print, pszUnit);
 
3537
                }
 
3538
#else /* !RT_OS_WINDOWS */
 
3539
                if (   enmFsTypeFile == RTFSTYPE_FAT
 
3540
                    || enmFsTypeFile == RTFSTYPE_EXT
 
3541
                    || enmFsTypeFile == RTFSTYPE_EXT2
 
3542
                    || enmFsTypeFile == RTFSTYPE_EXT3
 
3543
                    || enmFsTypeFile == RTFSTYPE_EXT4)
 
3544
                {
 
3545
                    RTFILE file;
 
3546
                    rc = RTFileOpen(&file, utfFile.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
 
3547
                    if (RT_SUCCESS(rc))
 
3548
                    {
 
3549
                        RTFOFF maxSize;
 
3550
                        /* Careful: This function will work only on selected local file systems! */
 
3551
                        rc = RTFileGetMaxSizeEx(file, &maxSize);
 
3552
                        RTFileClose(file);
 
3553
                        if (   RT_SUCCESS(rc)
 
3554
                            && maxSize > 0
 
3555
                            && i64Size > (LONG64)maxSize)
 
3556
                        {
 
3557
                            const char *pszUnitSiz;
 
3558
                            const char *pszUnitMax;
 
3559
                            uint64_t u64PrintSiz = formatDiskSize((LONG64)i64Size, &pszUnitSiz);
 
3560
                            uint64_t u64PrintMax = formatDiskSize(maxSize, &pszUnitMax);
 
3561
                            setVMRuntimeErrorCallbackF(0, "FatPartitionDetected", /* <= not exact but ... */
 
3562
                                    N_("The medium '%ls' has a logical size of %RU64%s "
 
3563
                                    "but the file system the medium is located on can "
 
3564
                                    "only handle files up to %RU64%s in theory.\n"
 
3565
                                    "We strongly recommend to put all your virtual disk "
 
3566
                                    "images and the snapshot folder onto a proper "
 
3567
                                    "file system (e.g. ext3) with a sufficient size"),
 
3568
                                    strFile.raw(), u64PrintSiz, pszUnitSiz, u64PrintMax, pszUnitMax);
 
3569
                        }
 
3570
                    }
 
3571
                }
 
3572
#endif /* !RT_OS_WINDOWS */
 
3573
 
 
3574
                /*
 
3575
                 * Snapshot folder:
 
3576
                 * Here we test only for a FAT partition as we had to create a dummy file otherwise
 
3577
                 */
 
3578
                if (   enmFsTypeSnap == RTFSTYPE_FAT
 
3579
                    && i64Size >= _4G
 
3580
                    && !mfSnapshotFolderSizeWarningShown)
 
3581
                {
 
3582
                    const char *pszUnit;
 
3583
                    uint64_t u64Print = formatDiskSize(i64Size, &pszUnit);
 
3584
                    setVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
 
3585
#ifdef RT_OS_WINDOWS
 
3586
                            N_("The snapshot folder of this VM '%ls' seems to be located on "
 
3587
                            "a FAT(32) file system. The logical size of the medium '%ls' "
 
3588
                            "(%RU64%s) is bigger than the maximum file size this file "
 
3589
                            "system can handle (4GB).\n"
 
3590
                            "We strongly recommend to put all your virtual disk images and "
 
3591
                            "the snapshot folder onto an NTFS partition"),
 
3592
#else
 
3593
                            N_("The snapshot folder of this VM '%ls' seems to be located on "
 
3594
                                "a FAT(32) file system. The logical size of the medium '%ls' "
 
3595
                                "(%RU64%s) is bigger than the maximum file size this file "
 
3596
                                "system can handle (4GB).\n"
 
3597
                                "We strongly recommend to put all your virtual disk images and "
 
3598
                                "the snapshot folder onto a proper file system (e.g. ext3)"),
 
3599
#endif
 
3600
                            strSnap.raw(), strFile.raw(), u64Print, pszUnit);
 
3601
                    /* Show this particular warning only once */
 
3602
                    mfSnapshotFolderSizeWarningShown = true;
 
3603
                }
 
3604
 
 
3605
#ifdef RT_OS_LINUX
 
3606
                /*
 
3607
                 * Ext4 bug: Check if the host I/O cache is disabled and the disk image is located
 
3608
                 *           on an ext4 partition. Later we have to check the Linux kernel version!
 
3609
                 * This bug apparently applies to the XFS file system as well.
 
3610
                 * Linux 2.6.36 is known to be fixed (tested with 2.6.36-rc4).
 
3611
                 */
 
3612
 
 
3613
                char szOsRelease[128];
 
3614
                rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOsRelease, sizeof(szOsRelease));
 
3615
                bool fKernelHasODirectBug =    RT_FAILURE(rc)
 
3616
                                            || (RTStrVersionCompare(szOsRelease, "2.6.36-rc4") < 0);
 
3617
 
 
3618
                if (   (uCaps & MediumFormatCapabilities_Asynchronous)
 
3619
                    && !fUseHostIOCache
 
3620
                    && fKernelHasODirectBug)
 
3621
                {
 
3622
                    if (   enmFsTypeFile == RTFSTYPE_EXT4
 
3623
                        || enmFsTypeFile == RTFSTYPE_XFS)
 
3624
                    {
 
3625
                        setVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
 
3626
                                N_("The host I/O cache for at least one controller is disabled "
 
3627
                                   "and the medium '%ls' for this VM "
 
3628
                                   "is located on an %s partition. There is a known Linux "
 
3629
                                   "kernel bug which can lead to the corruption of the virtual "
 
3630
                                   "disk image under these conditions.\n"
 
3631
                                   "Either enable the host I/O cache permanently in the VM "
 
3632
                                   "settings or put the disk image and the snapshot folder "
 
3633
                                   "onto a different file system.\n"
 
3634
                                   "The host I/O cache will now be enabled for this medium"),
 
3635
                                strFile.raw(), enmFsTypeFile == RTFSTYPE_EXT4 ? "ext4" : "xfs");
 
3636
                        fUseHostIOCache = true;
 
3637
                    }
 
3638
                    else if (  (   enmFsTypeSnap == RTFSTYPE_EXT4
 
3639
                                || enmFsTypeSnap == RTFSTYPE_XFS)
 
3640
                             && !mfSnapshotFolderExt4WarningShown)
 
3641
                    {
 
3642
                        setVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
 
3643
                                N_("The host I/O cache for at least one controller is disabled "
 
3644
                                   "and the snapshot folder for this VM "
 
3645
                                   "is located on an %s partition. There is a known Linux "
 
3646
                                   "kernel bug which can lead to the corruption of the virtual "
 
3647
                                   "disk image under these conditions.\n"
 
3648
                                   "Either enable the host I/O cache permanently in the VM "
 
3649
                                   "settings or put the disk image and the snapshot folder "
 
3650
                                   "onto a different file system.\n"
 
3651
                                   "The host I/O cache will now be enabled for this medium"),
 
3652
                                enmFsTypeSnap == RTFSTYPE_EXT4 ? "ext4" : "xfs");
 
3653
                        fUseHostIOCache = true;
 
3654
                        mfSnapshotFolderExt4WarningShown = true;
 
3655
                    }
 
3656
                }
 
3657
#endif
 
3658
            }
 
3659
        }
 
3660
 
 
3661
        if (pMedium)
 
3662
        {
 
3663
            BOOL fHostDrive;
 
3664
            hrc = pMedium->COMGETTER(HostDrive)(&fHostDrive);                               H();
 
3665
            if (  (   lType == DeviceType_DVD
 
3666
                   || lType == DeviceType_Floppy)
 
3667
                && !fHostDrive)
 
3668
            {
 
3669
                /*
 
3670
                 * Informative logging.
 
3671
                 */
 
3672
                Bstr strFile;
 
3673
                hrc = pMedium->COMGETTER(Location)(strFile.asOutParam());                   H();
 
3674
                Utf8Str utfFile = Utf8Str(strFile);
 
3675
                RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
 
3676
                (void)RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
 
3677
                LogRel(("File system of '%s' (%s) is %s\n",
 
3678
                       utfFile.c_str(), lType == DeviceType_DVD ? "DVD" : "Floppy",
 
3679
                       RTFsTypeName(enmFsTypeFile)));
 
3680
            }
 
3681
        }
 
3682
 
 
3683
        BOOL fPassthrough;
 
3684
        hrc = pMediumAtt->COMGETTER(Passthrough)(&fPassthrough);                            H();
 
3685
 
 
3686
        ComObjPtr<IBandwidthGroup> pBwGroup;
 
3687
        Bstr strBwGroup;
 
3688
        hrc = pMediumAtt->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam());                 H();
 
3689
 
 
3690
        if (!pBwGroup.isNull())
 
3691
        {
 
3692
            hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam());                       H();
 
3693
        }
 
3694
 
 
3695
        rc = configMedium(pLunL0,
 
3696
                          !!fPassthrough,
 
3697
                          lType,
 
3698
                          fUseHostIOCache,
 
3699
                          fBuiltinIOCache,
 
3700
                          fSetupMerge,
 
3701
                          uMergeSource,
 
3702
                          uMergeTarget,
 
3703
                          strBwGroup.isEmpty() ? NULL : Utf8Str(strBwGroup).c_str(),
 
3704
                          !!fDiscard,
 
3705
                          pMedium,
 
3706
                          aMachineState,
 
3707
                          phrc);
 
3708
        if (RT_FAILURE(rc))
 
3709
            return rc;
 
3710
 
 
3711
        if (fAttachDetach)
 
3712
        {
 
3713
            /* Attach the new driver. */
 
3714
            rc = PDMR3DeviceAttach(pUVM, pcszDevice, uInstance, uLUN,
 
3715
                                   fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
 
3716
            AssertRCReturn(rc, rc);
 
3717
 
 
3718
            /*
 
3719
             * Make the secret key helper interface known to the VD driver if it is attached,
 
3720
             * so we can get notified about missing keys.
 
3721
             */
 
3722
            PPDMIBASE pIBase = NULL;
 
3723
            rc = PDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "VD", &pIBase);
 
3724
            if (RT_SUCCESS(rc) && pIBase)
 
3725
            {
 
3726
                PPDMIMEDIA pIMedium = (PPDMIMEDIA)pIBase->pfnQueryInterface(pIBase, PDMIMEDIA_IID);
 
3727
                if (pIMedium)
 
3728
                {
 
3729
                    rc = pIMedium->pfnSetSecKeyIf(pIMedium, NULL, mpIfSecKeyHlp);
 
3730
                    Assert(RT_SUCCESS(rc) || rc == VERR_NOT_SUPPORTED);
 
3731
                }
 
3732
            }
 
3733
 
 
3734
            /* There is no need to handle removable medium mounting, as we
 
3735
             * unconditionally replace everthing including the block driver level.
 
3736
             * This means the new medium will be picked up automatically. */
 
3737
        }
 
3738
 
 
3739
        if (paLedDevType)
 
3740
            paLedDevType[uLUN] = lType;
 
3741
    }
 
3742
    catch (ConfigError &x)
 
3743
    {
 
3744
        // InsertConfig threw something:
 
3745
        return x.m_vrc;
 
3746
    }
 
3747
 
 
3748
#undef H
 
3749
 
 
3750
    return VINF_SUCCESS;
 
3751
}
 
3752
 
 
3753
int Console::configMedium(PCFGMNODE pLunL0,
 
3754
                          bool fPassthrough,
 
3755
                          DeviceType_T enmType,
 
3756
                          bool fUseHostIOCache,
 
3757
                          bool fBuiltinIOCache,
 
3758
                          bool fSetupMerge,
 
3759
                          unsigned uMergeSource,
 
3760
                          unsigned uMergeTarget,
 
3761
                          const char *pcszBwGroup,
 
3762
                          bool fDiscard,
 
3763
                          IMedium *pMedium,
 
3764
                          MachineState_T aMachineState,
 
3765
                          HRESULT *phrc)
 
3766
{
 
3767
    // InsertConfig* throws
 
3768
    try
 
3769
    {
 
3770
        int rc = VINF_SUCCESS;
 
3771
        HRESULT hrc;
 
3772
        Bstr bstr;
 
3773
        PCFGMNODE pLunL1 = NULL;
 
3774
        PCFGMNODE pCfg = NULL;
 
3775
 
 
3776
#define H() \
 
3777
    AssertMsgReturnStmt(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), if (phrc) *phrc = hrc, Global::vboxStatusCodeFromCOM(hrc))
 
3778
 
 
3779
 
 
3780
        BOOL fHostDrive = FALSE;
 
3781
        MediumType_T mediumType  = MediumType_Normal;
 
3782
        if (pMedium)
 
3783
        {
 
3784
            hrc = pMedium->COMGETTER(HostDrive)(&fHostDrive);                               H();
 
3785
            hrc = pMedium->COMGETTER(Type)(&mediumType);                                    H();
 
3786
        }
 
3787
 
 
3788
        if (fHostDrive)
 
3789
        {
 
3790
            Assert(pMedium);
 
3791
            if (enmType == DeviceType_DVD)
 
3792
            {
 
3793
                InsertConfigString(pLunL0, "Driver", "HostDVD");
 
3794
                InsertConfigNode(pLunL0, "Config", &pCfg);
 
3795
 
 
3796
                hrc = pMedium->COMGETTER(Location)(bstr.asOutParam());                      H();
 
3797
                InsertConfigString(pCfg, "Path", bstr);
 
3798
 
 
3799
                InsertConfigInteger(pCfg, "Passthrough", fPassthrough);
 
3800
            }
 
3801
            else if (enmType == DeviceType_Floppy)
 
3802
            {
 
3803
                InsertConfigString(pLunL0, "Driver", "HostFloppy");
 
3804
                InsertConfigNode(pLunL0, "Config", &pCfg);
 
3805
 
 
3806
                hrc = pMedium->COMGETTER(Location)(bstr.asOutParam());                      H();
 
3807
                InsertConfigString(pCfg, "Path", bstr);
 
3808
            }
 
3809
        }
 
3810
        else
 
3811
        {
 
3812
            InsertConfigString(pLunL0, "Driver", "Block");
 
3813
            InsertConfigNode(pLunL0, "Config", &pCfg);
 
3814
            switch (enmType)
 
3815
            {
 
3816
                case DeviceType_DVD:
 
3817
                    InsertConfigString(pCfg, "Type", "DVD");
 
3818
                    InsertConfigInteger(pCfg, "Mountable", 1);
 
3819
                    break;
 
3820
                case DeviceType_Floppy:
 
3821
                    InsertConfigString(pCfg, "Type", "Floppy 1.44");
 
3822
                    InsertConfigInteger(pCfg, "Mountable", 1);
 
3823
                    break;
 
3824
                case DeviceType_HardDisk:
 
3825
                default:
 
3826
                    InsertConfigString(pCfg, "Type", "HardDisk");
 
3827
                    InsertConfigInteger(pCfg, "Mountable", 0);
 
3828
            }
 
3829
 
 
3830
            if (    pMedium
 
3831
                && (   enmType == DeviceType_DVD
 
3832
                    || enmType == DeviceType_Floppy)
 
3833
               )
 
3834
            {
 
3835
                // if this medium represents an ISO image and this image is inaccessible,
 
3836
                // the ignore it instead of causing a failure; this can happen when we
 
3837
                // restore a VM state and the ISO has disappeared, e.g. because the Guest
 
3838
                // Additions were mounted and the user upgraded VirtualBox. Previously
 
3839
                // we failed on startup, but that's not good because the only way out then
 
3840
                // would be to discard the VM state...
 
3841
                MediumState_T mediumState;
 
3842
                hrc = pMedium->RefreshState(&mediumState);                                  H();
 
3843
                if (mediumState == MediumState_Inaccessible)
 
3844
                {
 
3845
                    Bstr loc;
 
3846
                    hrc = pMedium->COMGETTER(Location)(loc.asOutParam());                   H();
 
3847
                    setVMRuntimeErrorCallbackF(0, "DvdOrFloppyImageInaccessible",
 
3848
                                               "The image file '%ls' is inaccessible and is being ignored. Please select a different image file for the virtual %s drive.",
 
3849
                                               loc.raw(),
 
3850
                                               enmType == DeviceType_DVD ? "DVD" : "floppy");
 
3851
                    pMedium = NULL;
 
3852
                }
 
3853
            }
 
3854
 
 
3855
            if (pMedium)
 
3856
            {
 
3857
                /* Start with length of parent chain, as the list is reversed */
 
3858
                unsigned uImage = 0;
 
3859
                IMedium *pTmp = pMedium;
 
3860
                while (pTmp)
 
3861
                {
 
3862
                    uImage++;
 
3863
                    hrc = pTmp->COMGETTER(Parent)(&pTmp);                                   H();
 
3864
                }
 
3865
                /* Index of last image */
 
3866
                uImage--;
 
3867
 
 
3868
#if 0 /* Enable for I/O debugging */
 
3869
                InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
 
3870
                InsertConfigString(pLunL0, "Driver", "DiskIntegrity");
 
3871
                InsertConfigNode(pLunL0, "Config", &pCfg);
 
3872
                InsertConfigInteger(pCfg, "CheckConsistency", 0);
 
3873
                InsertConfigInteger(pCfg, "CheckDoubleCompletions", 1);
 
3874
#endif
 
3875
 
 
3876
                InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
 
3877
                InsertConfigString(pLunL1, "Driver", "VD");
 
3878
                InsertConfigNode(pLunL1, "Config", &pCfg);
 
3879
 
 
3880
# ifdef VBOX_WITH_EXTPACK
 
3881
                static const Utf8Str strExtPackPuel("Oracle VM VirtualBox Extension Pack");
 
3882
                static const char *s_pszVDPlugin = "VDPluginCrypt";
 
3883
                if (mptrExtPackManager->isExtPackUsable(strExtPackPuel.c_str()))
 
3884
                {
 
3885
                    /* Configure loading the VDPlugin. */
 
3886
                    PCFGMNODE pCfgPlugins = NULL;
 
3887
                    PCFGMNODE pCfgPlugin = NULL;
 
3888
                    Utf8Str strPlugin;
 
3889
                    hrc = mptrExtPackManager->getLibraryPathForExtPack(s_pszVDPlugin, &strExtPackPuel, &strPlugin);
 
3890
                    // Don't fail, this is optional!
 
3891
                    if (SUCCEEDED(hrc))
 
3892
                    {
 
3893
                        InsertConfigNode(pCfg, "Plugins", &pCfgPlugins);
 
3894
                        InsertConfigNode(pCfgPlugins, s_pszVDPlugin, &pCfgPlugin);
 
3895
                        InsertConfigString(pCfgPlugin, "Path", strPlugin.c_str());
 
3896
                    }
 
3897
                }
 
3898
# endif
 
3899
 
 
3900
                hrc = pMedium->COMGETTER(Location)(bstr.asOutParam());                      H();
 
3901
                InsertConfigString(pCfg, "Path", bstr);
 
3902
 
 
3903
                hrc = pMedium->COMGETTER(Format)(bstr.asOutParam());                        H();
 
3904
                InsertConfigString(pCfg, "Format", bstr);
 
3905
 
 
3906
                if (mediumType == MediumType_Readonly)
 
3907
                    InsertConfigInteger(pCfg, "ReadOnly", 1);
 
3908
                else if (enmType == DeviceType_Floppy)
 
3909
                    InsertConfigInteger(pCfg, "MaybeReadOnly", 1);
 
3910
 
 
3911
                /* Start without exclusive write access to the images. */
 
3912
                /** @todo Live Migration: I don't quite like this, we risk screwing up when
 
3913
                 *        we're resuming the VM if some 3rd dude have any of the VDIs open
 
3914
                 *        with write sharing denied.  However, if the two VMs are sharing a
 
3915
                 *        image it really is necessary....
 
3916
                 *
 
3917
                 *        So, on the "lock-media" command, the target teleporter should also
 
3918
                 *        make DrvVD undo TempReadOnly.  It gets interesting if we fail after
 
3919
                 *        that. Grumble. */
 
3920
                if (   enmType == DeviceType_HardDisk
 
3921
                    && (   aMachineState == MachineState_TeleportingIn
 
3922
                        || aMachineState == MachineState_FaultTolerantSyncing))
 
3923
                    InsertConfigInteger(pCfg, "TempReadOnly", 1);
 
3924
 
 
3925
                /* Flag for opening the medium for sharing between VMs. This
 
3926
                 * is done at the moment only for the first (and only) medium
 
3927
                 * in the chain, as shared media can have no diffs. */
 
3928
                if (mediumType == MediumType_Shareable)
 
3929
                    InsertConfigInteger(pCfg, "Shareable", 1);
 
3930
 
 
3931
                if (!fUseHostIOCache)
 
3932
                {
 
3933
                    InsertConfigInteger(pCfg, "UseNewIo", 1);
 
3934
                    /*
 
3935
                     * Activate the builtin I/O cache for harddisks only.
 
3936
                     * It caches writes only which doesn't make sense for DVD drives
 
3937
                     * and just increases the overhead.
 
3938
                     */
 
3939
                    if (   fBuiltinIOCache
 
3940
                        && (enmType == DeviceType_HardDisk))
 
3941
                        InsertConfigInteger(pCfg, "BlockCache", 1);
 
3942
                }
 
3943
 
 
3944
                if (fSetupMerge)
 
3945
                {
 
3946
                    InsertConfigInteger(pCfg, "SetupMerge", 1);
 
3947
                    if (uImage == uMergeSource)
 
3948
                        InsertConfigInteger(pCfg, "MergeSource", 1);
 
3949
                    else if (uImage == uMergeTarget)
 
3950
                        InsertConfigInteger(pCfg, "MergeTarget", 1);
 
3951
                }
 
3952
 
 
3953
                switch (enmType)
 
3954
                {
 
3955
                    case DeviceType_DVD:
 
3956
                        InsertConfigString(pCfg, "Type", "DVD");
 
3957
                        break;
 
3958
                    case DeviceType_Floppy:
 
3959
                        InsertConfigString(pCfg, "Type", "Floppy");
 
3960
                        break;
 
3961
                    case DeviceType_HardDisk:
 
3962
                    default:
 
3963
                        InsertConfigString(pCfg, "Type", "HardDisk");
 
3964
                }
 
3965
 
 
3966
                if (pcszBwGroup)
 
3967
                    InsertConfigString(pCfg, "BwGroup", pcszBwGroup);
 
3968
 
 
3969
                if (fDiscard)
 
3970
                    InsertConfigInteger(pCfg, "Discard", 1);
 
3971
 
 
3972
                /* Pass all custom parameters. */
 
3973
                bool fHostIP = true;
 
3974
                hrc = configMediumProperties(pCfg, pMedium, &fHostIP); H();
 
3975
 
 
3976
                /* Create an inverted list of parents. */
 
3977
                uImage--;
 
3978
                IMedium *pParentMedium = pMedium;
 
3979
                for (PCFGMNODE pParent = pCfg;; uImage--)
 
3980
                {
 
3981
                    hrc = pParentMedium->COMGETTER(Parent)(&pMedium);                       H();
 
3982
                    if (!pMedium)
 
3983
                        break;
 
3984
 
 
3985
                    PCFGMNODE pCur;
 
3986
                    InsertConfigNode(pParent, "Parent", &pCur);
 
3987
                    hrc = pMedium->COMGETTER(Location)(bstr.asOutParam());                  H();
 
3988
                    InsertConfigString(pCur, "Path", bstr);
 
3989
 
 
3990
                    hrc = pMedium->COMGETTER(Format)(bstr.asOutParam());                    H();
 
3991
                    InsertConfigString(pCur, "Format", bstr);
 
3992
 
 
3993
                    if (fSetupMerge)
 
3994
                    {
 
3995
                        if (uImage == uMergeSource)
 
3996
                            InsertConfigInteger(pCur, "MergeSource", 1);
 
3997
                        else if (uImage == uMergeTarget)
 
3998
                            InsertConfigInteger(pCur, "MergeTarget", 1);
 
3999
                    }
 
4000
 
 
4001
                    /* Configure medium properties. */
 
4002
                    hrc = configMediumProperties(pCur, pMedium, &fHostIP); H();
 
4003
 
 
4004
                    /* next */
 
4005
                    pParent = pCur;
 
4006
                    pParentMedium = pMedium;
 
4007
                }
 
4008
 
 
4009
                /* Custom code: put marker to not use host IP stack to driver
 
4010
                 * configuration node. Simplifies life of DrvVD a bit. */
 
4011
                if (!fHostIP)
 
4012
                    InsertConfigInteger(pCfg, "HostIPStack", 0);
 
4013
            }
 
4014
        }
 
4015
#undef H
 
4016
    }
 
4017
    catch (ConfigError &x)
 
4018
    {
 
4019
        // InsertConfig threw something:
 
4020
        return x.m_vrc;
 
4021
    }
 
4022
 
 
4023
    return VINF_SUCCESS;
 
4024
}
 
4025
 
 
4026
/**
 
4027
 * Adds the medium properties to the CFGM tree.
 
4028
 *
 
4029
 * @returns VBox status code.
 
4030
 * @param   pCur       The current CFGM node.
 
4031
 * @param   pMedium    The medium object to configure.
 
4032
 * @param   pfHostIP   Where to return the value of the \"HostIPStack\" property if found.
 
4033
 */
 
4034
int Console::configMediumProperties(PCFGMNODE pCur, IMedium *pMedium, bool *pfHostIP)
 
4035
{
 
4036
    /* Pass all custom parameters. */
 
4037
    SafeArray<BSTR> aNames;
 
4038
    SafeArray<BSTR> aValues;
 
4039
    HRESULT hrc = pMedium->GetProperties(NULL, ComSafeArrayAsOutParam(aNames),
 
4040
                                         ComSafeArrayAsOutParam(aValues));
 
4041
 
 
4042
    if (   SUCCEEDED(hrc)
 
4043
        && aNames.size() != 0)
 
4044
    {
 
4045
        PCFGMNODE pVDC;
 
4046
        InsertConfigNode(pCur, "VDConfig", &pVDC);
 
4047
        for (size_t ii = 0; ii < aNames.size(); ++ii)
 
4048
        {
 
4049
            if (aValues[ii] && *aValues[ii])
 
4050
            {
 
4051
                Utf8Str name = aNames[ii];
 
4052
                Utf8Str value = aValues[ii];
 
4053
                size_t offSlash = name.find("/", 0);
 
4054
                if (   offSlash != name.npos
 
4055
                    && !name.startsWith("Special/"))
 
4056
                {
 
4057
                    com::Utf8Str strFilter;
 
4058
                    com::Utf8Str strKey;
 
4059
 
 
4060
                    hrc = strFilter.assignEx(name, 0, offSlash);
 
4061
                    if (FAILED(hrc))
 
4062
                        break;
 
4063
 
 
4064
                    hrc = strKey.assignEx(name, offSlash + 1, name.length() - offSlash - 1); /* Skip slash */
 
4065
                    if (FAILED(hrc))
 
4066
                        break;
 
4067
 
 
4068
                    PCFGMNODE pCfgFilterConfig = CFGMR3GetChild(pVDC, strFilter.c_str());
 
4069
                    if (!pCfgFilterConfig)
 
4070
                        InsertConfigNode(pVDC, strFilter.c_str(), &pCfgFilterConfig);
 
4071
 
 
4072
                    InsertConfigString(pCfgFilterConfig, strKey.c_str(), value);
 
4073
                }
 
4074
                else
 
4075
                {
 
4076
                    InsertConfigString(pVDC, name.c_str(), value);
 
4077
                    if (    name.compare("HostIPStack") == 0
 
4078
                        &&  value.compare("0") == 0)
 
4079
                        *pfHostIP = false;
 
4080
                }
 
4081
            }
 
4082
        }
 
4083
    }
 
4084
 
 
4085
    return hrc;
 
4086
}
 
4087
 
 
4088
/**
 
4089
 *  Construct the Network configuration tree
 
4090
 *
 
4091
 *  @returns VBox status code.
 
4092
 *
 
4093
 *  @param   pszDevice           The PDM device name.
 
4094
 *  @param   uInstance           The PDM device instance.
 
4095
 *  @param   uLun                The PDM LUN number of the drive.
 
4096
 *  @param   aNetworkAdapter     The network adapter whose attachment needs to be changed
 
4097
 *  @param   pCfg                Configuration node for the device
 
4098
 *  @param   pLunL0              To store the pointer to the LUN#0.
 
4099
 *  @param   pInst               The instance CFGM node
 
4100
 *  @param   fAttachDetach       To determine if the network attachment should
 
4101
 *                               be attached/detached after/before
 
4102
 *                               configuration.
 
4103
 *  @param   fIgnoreConnectFailure
 
4104
 *                               True if connection failures should be ignored
 
4105
 *                               (makes only sense for bridged/host-only networks).
 
4106
 *
 
4107
 *  @note   Locks this object for writing.
 
4108
 *  @thread EMT
 
4109
 */
 
4110
int Console::configNetwork(const char *pszDevice,
 
4111
                           unsigned uInstance,
 
4112
                           unsigned uLun,
 
4113
                           INetworkAdapter *aNetworkAdapter,
 
4114
                           PCFGMNODE pCfg,
 
4115
                           PCFGMNODE pLunL0,
 
4116
                           PCFGMNODE pInst,
 
4117
                           bool fAttachDetach,
 
4118
                           bool fIgnoreConnectFailure)
 
4119
{
 
4120
    AutoCaller autoCaller(this);
 
4121
    AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED);
 
4122
 
 
4123
    // InsertConfig* throws
 
4124
    try
 
4125
    {
 
4126
        int rc = VINF_SUCCESS;
 
4127
        HRESULT hrc;
 
4128
        Bstr bstr;
 
4129
 
 
4130
#define H()         AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
 
4131
 
 
4132
        /*
 
4133
         * Locking the object before doing VMR3* calls is quite safe here, since
 
4134
         * we're on EMT. Write lock is necessary because we indirectly modify the
 
4135
         * meAttachmentType member.
 
4136
         */
 
4137
        AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
4138
 
 
4139
        ComPtr<IMachine> pMachine = machine();
 
4140
 
 
4141
        ComPtr<IVirtualBox> virtualBox;
 
4142
        hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam());                         H();
 
4143
 
 
4144
        ComPtr<IHost> host;
 
4145
        hrc = virtualBox->COMGETTER(Host)(host.asOutParam());                               H();
 
4146
 
 
4147
        BOOL fSniffer;
 
4148
        hrc = aNetworkAdapter->COMGETTER(TraceEnabled)(&fSniffer);                          H();
 
4149
 
 
4150
        NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy;
 
4151
        hrc = aNetworkAdapter->COMGETTER(PromiscModePolicy)(&enmPromiscModePolicy);         H();
 
4152
        const char *pszPromiscuousGuestPolicy;
 
4153
        switch (enmPromiscModePolicy)
 
4154
        {
 
4155
            case NetworkAdapterPromiscModePolicy_Deny:          pszPromiscuousGuestPolicy = "deny"; break;
 
4156
            case NetworkAdapterPromiscModePolicy_AllowNetwork:  pszPromiscuousGuestPolicy = "allow-network"; break;
 
4157
            case NetworkAdapterPromiscModePolicy_AllowAll:      pszPromiscuousGuestPolicy = "allow-all"; break;
 
4158
            default: AssertFailedReturn(VERR_INTERNAL_ERROR_4);
 
4159
        }
 
4160
 
 
4161
        if (fAttachDetach)
 
4162
        {
 
4163
            rc = PDMR3DeviceDetach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/);
 
4164
            if (rc == VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN)
 
4165
                rc = VINF_SUCCESS;
 
4166
            AssertLogRelRCReturn(rc, rc);
 
4167
 
 
4168
            /* nuke anything which might have been left behind. */
 
4169
            CFGMR3RemoveNode(CFGMR3GetChildF(pInst, "LUN#%u", uLun));
 
4170
        }
 
4171
 
 
4172
#ifdef VBOX_WITH_NETSHAPER
 
4173
        ComObjPtr<IBandwidthGroup> pBwGroup;
 
4174
        Bstr strBwGroup;
 
4175
        hrc = aNetworkAdapter->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam());            H();
 
4176
 
 
4177
        if (!pBwGroup.isNull())
 
4178
        {
 
4179
            hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam());                       H();
 
4180
        }
 
4181
#endif /* VBOX_WITH_NETSHAPER */
 
4182
 
 
4183
        Utf8Str strNetDriver;
 
4184
 
 
4185
 
 
4186
        InsertConfigNode(pInst, "LUN#0", &pLunL0);
 
4187
 
 
4188
#ifdef VBOX_WITH_NETSHAPER
 
4189
        if (!strBwGroup.isEmpty())
 
4190
        {
 
4191
            InsertConfigString(pLunL0, "Driver", "NetShaper");
 
4192
            InsertConfigNode(pLunL0, "Config", &pCfg);
 
4193
            InsertConfigString(pCfg, "BwGroup", strBwGroup);
 
4194
            InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
 
4195
        }
 
4196
#endif /* VBOX_WITH_NETSHAPER */
 
4197
 
 
4198
        if (fSniffer)
 
4199
        {
 
4200
            InsertConfigString(pLunL0, "Driver", "NetSniffer");
 
4201
            InsertConfigNode(pLunL0, "Config", &pCfg);
 
4202
            hrc = aNetworkAdapter->COMGETTER(TraceFile)(bstr.asOutParam());             H();
 
4203
            if (!bstr.isEmpty()) /* check convention for indicating default file. */
 
4204
                InsertConfigString(pCfg, "File", bstr);
 
4205
            InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
 
4206
        }
 
4207
 
 
4208
 
 
4209
        Bstr networkName, trunkName, trunkType;
 
4210
        NetworkAttachmentType_T eAttachmentType;
 
4211
        hrc = aNetworkAdapter->COMGETTER(AttachmentType)(&eAttachmentType);                 H();
 
4212
        switch (eAttachmentType)
 
4213
        {
 
4214
            case NetworkAttachmentType_Null:
 
4215
                break;
 
4216
 
 
4217
            case NetworkAttachmentType_NAT:
 
4218
            {
 
4219
                ComPtr<INATEngine> natEngine;
 
4220
                hrc = aNetworkAdapter->COMGETTER(NATEngine)(natEngine.asOutParam());        H();
 
4221
                InsertConfigString(pLunL0, "Driver", "NAT");
 
4222
                InsertConfigNode(pLunL0, "Config", &pCfg);
 
4223
 
 
4224
                /* Configure TFTP prefix and boot filename. */
 
4225
                hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam());                 H();
 
4226
                if (!bstr.isEmpty())
 
4227
                    InsertConfigString(pCfg, "TFTPPrefix", Utf8StrFmt("%ls%c%s", bstr.raw(), RTPATH_DELIMITER, "TFTP"));
 
4228
                hrc = pMachine->COMGETTER(Name)(bstr.asOutParam());                         H();
 
4229
                InsertConfigString(pCfg, "BootFile", Utf8StrFmt("%ls.pxe", bstr.raw()));
 
4230
 
 
4231
                hrc = natEngine->COMGETTER(Network)(bstr.asOutParam());                     H();
 
4232
                if (!bstr.isEmpty())
 
4233
                    InsertConfigString(pCfg, "Network", bstr);
 
4234
                else
 
4235
                {
 
4236
                    ULONG uSlot;
 
4237
                    hrc = aNetworkAdapter->COMGETTER(Slot)(&uSlot);                         H();
 
4238
                    InsertConfigString(pCfg, "Network", Utf8StrFmt("10.0.%d.0/24", uSlot+2));
 
4239
                }
 
4240
                hrc = natEngine->COMGETTER(HostIP)(bstr.asOutParam());                      H();
 
4241
                if (!bstr.isEmpty())
 
4242
                    InsertConfigString(pCfg, "BindIP", bstr);
 
4243
                ULONG mtu = 0;
 
4244
                ULONG sockSnd = 0;
 
4245
                ULONG sockRcv = 0;
 
4246
                ULONG tcpSnd = 0;
 
4247
                ULONG tcpRcv = 0;
 
4248
                hrc = natEngine->GetNetworkSettings(&mtu, &sockSnd, &sockRcv, &tcpSnd, &tcpRcv); H();
 
4249
                if (mtu)
 
4250
                    InsertConfigInteger(pCfg, "SlirpMTU", mtu);
 
4251
                if (sockRcv)
 
4252
                    InsertConfigInteger(pCfg, "SockRcv", sockRcv);
 
4253
                if (sockSnd)
 
4254
                    InsertConfigInteger(pCfg, "SockSnd", sockSnd);
 
4255
                if (tcpRcv)
 
4256
                    InsertConfigInteger(pCfg, "TcpRcv", tcpRcv);
 
4257
                if (tcpSnd)
 
4258
                    InsertConfigInteger(pCfg, "TcpSnd", tcpSnd);
 
4259
                hrc = natEngine->COMGETTER(TFTPPrefix)(bstr.asOutParam());                  H();
 
4260
                if (!bstr.isEmpty())
 
4261
                {
 
4262
                    RemoveConfigValue(pCfg, "TFTPPrefix");
 
4263
                    InsertConfigString(pCfg, "TFTPPrefix", bstr);
 
4264
                }
 
4265
                hrc = natEngine->COMGETTER(TFTPBootFile)(bstr.asOutParam());                H();
 
4266
                if (!bstr.isEmpty())
 
4267
                {
 
4268
                    RemoveConfigValue(pCfg, "BootFile");
 
4269
                    InsertConfigString(pCfg, "BootFile", bstr);
 
4270
                }
 
4271
                hrc = natEngine->COMGETTER(TFTPNextServer)(bstr.asOutParam());              H();
 
4272
                if (!bstr.isEmpty())
 
4273
                    InsertConfigString(pCfg, "NextServer", bstr);
 
4274
                BOOL fDNSFlag;
 
4275
                hrc = natEngine->COMGETTER(DNSPassDomain)(&fDNSFlag);                       H();
 
4276
                InsertConfigInteger(pCfg, "PassDomain", fDNSFlag);
 
4277
                hrc = natEngine->COMGETTER(DNSProxy)(&fDNSFlag);                            H();
 
4278
                InsertConfigInteger(pCfg, "DNSProxy", fDNSFlag);
 
4279
                hrc = natEngine->COMGETTER(DNSUseHostResolver)(&fDNSFlag);                  H();
 
4280
                InsertConfigInteger(pCfg, "UseHostResolver", fDNSFlag);
 
4281
 
 
4282
                ULONG aliasMode;
 
4283
                hrc = natEngine->COMGETTER(AliasMode)(&aliasMode);                          H();
 
4284
                InsertConfigInteger(pCfg, "AliasMode", aliasMode);
 
4285
 
 
4286
                /* port-forwarding */
 
4287
                SafeArray<BSTR> pfs;
 
4288
                hrc = natEngine->COMGETTER(Redirects)(ComSafeArrayAsOutParam(pfs));         H();
 
4289
                PCFGMNODE pPF = NULL;          /* /Devices/Dev/.../Config/PF#0/ */
 
4290
                for (unsigned int i = 0; i < pfs.size(); ++i)
 
4291
                {
 
4292
                    uint16_t port = 0;
 
4293
                    BSTR r = pfs[i];
 
4294
                    Utf8Str utf = Utf8Str(r);
 
4295
                    Utf8Str strName;
 
4296
                    Utf8Str strProto;
 
4297
                    Utf8Str strHostPort;
 
4298
                    Utf8Str strHostIP;
 
4299
                    Utf8Str strGuestPort;
 
4300
                    Utf8Str strGuestIP;
 
4301
                    size_t pos, ppos;
 
4302
                    pos = ppos = 0;
 
4303
#define ITERATE_TO_NEXT_TERM(res, str, pos, ppos) \
 
4304
    do { \
 
4305
        pos = str.find(",", ppos); \
 
4306
        if (pos == Utf8Str::npos) \
 
4307
        { \
 
4308
            Log(( #res " extracting from %s is failed\n", str.c_str())); \
 
4309
            continue; \
 
4310
        } \
 
4311
        res = str.substr(ppos, pos - ppos); \
 
4312
        Log2((#res " %s pos:%d, ppos:%d\n", res.c_str(), pos, ppos)); \
 
4313
        ppos = pos + 1; \
 
4314
    } while (0)
 
4315
                    ITERATE_TO_NEXT_TERM(strName, utf, pos, ppos);
 
4316
                    ITERATE_TO_NEXT_TERM(strProto, utf, pos, ppos);
 
4317
                    ITERATE_TO_NEXT_TERM(strHostIP, utf, pos, ppos);
 
4318
                    ITERATE_TO_NEXT_TERM(strHostPort, utf, pos, ppos);
 
4319
                    ITERATE_TO_NEXT_TERM(strGuestIP, utf, pos, ppos);
 
4320
                    strGuestPort = utf.substr(ppos, utf.length() - ppos);
 
4321
#undef ITERATE_TO_NEXT_TERM
 
4322
 
 
4323
                    uint32_t proto = strProto.toUInt32();
 
4324
                    bool fValid = true;
 
4325
                    switch (proto)
 
4326
                    {
 
4327
                        case NATProtocol_UDP:
 
4328
                            strProto = "UDP";
 
4329
                            break;
 
4330
                        case NATProtocol_TCP:
 
4331
                            strProto = "TCP";
 
4332
                            break;
 
4333
                        default:
 
4334
                            fValid = false;
 
4335
                    }
 
4336
                    /* continue with next rule if no valid proto was passed */
 
4337
                    if (!fValid)
 
4338
                        continue;
 
4339
 
 
4340
                    if (strName.isEmpty())
 
4341
                        VMSetError(VMR3GetVM(mpUVM), VERR_CFGM_NO_NODE, RT_SRC_POS,
 
4342
                                   N_("NAT redirection rule without a name"));
 
4343
 
 
4344
                    InsertConfigNode(pCfg, strName.c_str(), &pPF);
 
4345
                    InsertConfigString(pPF, "Protocol", strProto);
 
4346
 
 
4347
                    if (!strHostIP.isEmpty())
 
4348
                        InsertConfigString(pPF, "BindIP", strHostIP);
 
4349
 
 
4350
                    if (!strGuestIP.isEmpty())
 
4351
                        InsertConfigString(pPF, "GuestIP", strGuestIP);
 
4352
 
 
4353
                    port = RTStrToUInt16(strHostPort.c_str());
 
4354
                    if (port)
 
4355
                        InsertConfigInteger(pPF, "HostPort", port);
 
4356
 
 
4357
                    port = RTStrToUInt16(strGuestPort.c_str());
 
4358
                    if (port)
 
4359
                        InsertConfigInteger(pPF, "GuestPort", port);
 
4360
                }
 
4361
                break;
 
4362
            }
 
4363
 
 
4364
            case NetworkAttachmentType_Bridged:
 
4365
            {
 
4366
#if (defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)) && !defined(VBOX_WITH_NETFLT)
 
4367
                hrc = attachToTapInterface(aNetworkAdapter);
 
4368
                if (FAILED(hrc))
 
4369
                {
 
4370
                    switch (hrc)
 
4371
                    {
 
4372
                        case VERR_ACCESS_DENIED:
 
4373
                            return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,  N_(
 
4374
                                            "Failed to open '/dev/net/tun' for read/write access. Please check the "
 
4375
                                            "permissions of that node. Either run 'chmod 0666 /dev/net/tun' or "
 
4376
                                            "change the group of that node and make yourself a member of that group. Make "
 
4377
                                            "sure that these changes are permanent, especially if you are "
 
4378
                                            "using udev"));
 
4379
                        default:
 
4380
                            AssertMsgFailed(("Could not attach to host interface! Bad!\n"));
 
4381
                            return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
 
4382
                                            "Failed to initialize Host Interface Networking"));
 
4383
                    }
 
4384
                }
 
4385
 
 
4386
                Assert((int)maTapFD[uInstance] >= 0);
 
4387
                if ((int)maTapFD[uInstance] >= 0)
 
4388
                {
 
4389
                    InsertConfigString(pLunL0, "Driver", "HostInterface");
 
4390
                    InsertConfigNode(pLunL0, "Config", &pCfg);
 
4391
                    InsertConfigInteger(pCfg, "FileHandle", maTapFD[uInstance]);
 
4392
                }
 
4393
 
 
4394
#elif defined(VBOX_WITH_NETFLT)
 
4395
                /*
 
4396
                 * This is the new VBoxNetFlt+IntNet stuff.
 
4397
                 */
 
4398
                Bstr BridgedIfName;
 
4399
                hrc = aNetworkAdapter->COMGETTER(BridgedInterface)(BridgedIfName.asOutParam());
 
4400
                if (FAILED(hrc))
 
4401
                {
 
4402
                    LogRel(("NetworkAttachmentType_Bridged: COMGETTER(BridgedInterface) failed, hrc (0x%x)\n", hrc));
 
4403
                    H();
 
4404
                }
 
4405
 
 
4406
                Utf8Str BridgedIfNameUtf8(BridgedIfName);
 
4407
                const char *pszBridgedIfName = BridgedIfNameUtf8.c_str();
 
4408
 
 
4409
# if defined(RT_OS_DARWIN)
 
4410
                /* The name is on the form 'ifX: long name', chop it off at the colon. */
 
4411
                char szTrunk[8];
 
4412
                RTStrCopy(szTrunk, sizeof(szTrunk), pszBridgedIfName);
 
4413
                char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
 
4414
// Quick fix for @bugref{5633}
 
4415
//                 if (!pszColon)
 
4416
//                 {
 
4417
//                     /*
 
4418
//                     * Dynamic changing of attachment causes an attempt to configure
 
4419
//                     * network with invalid host adapter (as it is must be changed before
 
4420
//                     * the attachment), calling Detach here will cause a deadlock.
 
4421
//                     * See @bugref{4750}.
 
4422
//                     * hrc = aNetworkAdapter->Detach();                                   H();
 
4423
//                     */
 
4424
//                     return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
 
4425
//                                       N_("Malformed host interface networking name '%ls'"),
 
4426
//                                       BridgedIfName.raw());
 
4427
//                 }
 
4428
                if (pszColon)
 
4429
                    *pszColon = '\0';
 
4430
                const char *pszTrunk = szTrunk;
 
4431
 
 
4432
# elif defined(RT_OS_SOLARIS)
 
4433
                /* The name is on the form format 'ifX[:1] - long name, chop it off at space. */
 
4434
                char szTrunk[256];
 
4435
                strlcpy(szTrunk, pszBridgedIfName, sizeof(szTrunk));
 
4436
                char *pszSpace = (char *)memchr(szTrunk, ' ', sizeof(szTrunk));
 
4437
 
 
4438
                /*
 
4439
                 * Currently don't bother about malformed names here for the sake of people using
 
4440
                 * VBoxManage and setting only the NIC name from there. If there is a space we
 
4441
                 * chop it off and proceed, otherwise just use whatever we've got.
 
4442
                 */
 
4443
                if (pszSpace)
 
4444
                    *pszSpace = '\0';
 
4445
 
 
4446
                /* Chop it off at the colon (zone naming eg: e1000g:1 we need only the e1000g) */
 
4447
                char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
 
4448
                if (pszColon)
 
4449
                    *pszColon = '\0';
 
4450
 
 
4451
                const char *pszTrunk = szTrunk;
 
4452
 
 
4453
# elif defined(RT_OS_WINDOWS)
 
4454
                ComPtr<IHostNetworkInterface> hostInterface;
 
4455
                hrc = host->FindHostNetworkInterfaceByName(BridgedIfName.raw(),
 
4456
                                                           hostInterface.asOutParam());
 
4457
                if (!SUCCEEDED(hrc))
 
4458
                {
 
4459
                    AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: FindByName failed, rc=%Rhrc (0x%x)", hrc, hrc));
 
4460
                    return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
 
4461
                                      N_("Nonexistent host networking interface, name '%ls'"),
 
4462
                                      BridgedIfName.raw());
 
4463
                }
 
4464
 
 
4465
                HostNetworkInterfaceType_T eIfType;
 
4466
                hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
 
4467
                if (FAILED(hrc))
 
4468
                {
 
4469
                    LogRel(("NetworkAttachmentType_Bridged: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
 
4470
                    H();
 
4471
                }
 
4472
 
 
4473
                if (eIfType != HostNetworkInterfaceType_Bridged)
 
4474
                {
 
4475
                    return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
 
4476
                                      N_("Interface ('%ls') is not a Bridged Adapter interface"),
 
4477
                                      BridgedIfName.raw());
 
4478
                }
 
4479
 
 
4480
                hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
 
4481
                if (FAILED(hrc))
 
4482
                {
 
4483
                    LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
 
4484
                    H();
 
4485
                }
 
4486
                Guid hostIFGuid(bstr);
 
4487
 
 
4488
                INetCfg *pNc;
 
4489
                ComPtr<INetCfgComponent> pAdaptorComponent;
 
4490
                LPWSTR pszApp;
 
4491
 
 
4492
                hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
 
4493
                Assert(hrc == S_OK);
 
4494
                if (hrc != S_OK)
 
4495
                {
 
4496
                    LogRel(("NetworkAttachmentType_Bridged: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
 
4497
                    H();
 
4498
                }
 
4499
 
 
4500
                /* get the adapter's INetCfgComponent*/
 
4501
                hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(), pAdaptorComponent.asOutParam());
 
4502
                if (hrc != S_OK)
 
4503
                {
 
4504
                    VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
 
4505
                    LogRel(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)\n", hrc));
 
4506
                    H();
 
4507
                }
 
4508
#define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
 
4509
                char szTrunkName[INTNET_MAX_TRUNK_NAME];
 
4510
                char *pszTrunkName = szTrunkName;
 
4511
                wchar_t * pswzBindName;
 
4512
                hrc = pAdaptorComponent->GetBindName(&pswzBindName);
 
4513
                Assert(hrc == S_OK);
 
4514
                if (hrc == S_OK)
 
4515
                {
 
4516
                    int cwBindName = (int)wcslen(pswzBindName) + 1;
 
4517
                    int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
 
4518
                    if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
 
4519
                    {
 
4520
                        strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
 
4521
                        pszTrunkName += cbFullBindNamePrefix-1;
 
4522
                        if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
 
4523
                                                sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
 
4524
                        {
 
4525
                            DWORD err = GetLastError();
 
4526
                            hrc = HRESULT_FROM_WIN32(err);
 
4527
                            AssertMsgFailed(("%hrc=%Rhrc %#x\n", hrc, hrc));
 
4528
                            AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n", hrc, hrc, err));
 
4529
                        }
 
4530
                    }
 
4531
                    else
 
4532
                    {
 
4533
                        AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: insufficient szTrunkName buffer space\n"));
 
4534
                        /** @todo set appropriate error code */
 
4535
                        hrc = E_FAIL;
 
4536
                    }
 
4537
 
 
4538
                    if (hrc != S_OK)
 
4539
                    {
 
4540
                        AssertFailed();
 
4541
                        CoTaskMemFree(pswzBindName);
 
4542
                        VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
 
4543
                        H();
 
4544
                    }
 
4545
 
 
4546
                    /* we're not freeing the bind name since we'll use it later for detecting wireless*/
 
4547
                }
 
4548
                else
 
4549
                {
 
4550
                    VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
 
4551
                    AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)", hrc));
 
4552
                    H();
 
4553
                }
 
4554
 
 
4555
                const char *pszTrunk = szTrunkName;
 
4556
                /* we're not releasing the INetCfg stuff here since we use it later to figure out whether it is wireless */
 
4557
 
 
4558
# elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
 
4559
#  if defined(RT_OS_FREEBSD)
 
4560
                /*
 
4561
                 * If we bridge to a tap interface open it the `old' direct way.
 
4562
                 * This works and performs better than bridging a physical
 
4563
                 * interface via the current FreeBSD vboxnetflt implementation.
 
4564
                 */
 
4565
                if (!strncmp(pszBridgedIfName, RT_STR_TUPLE("tap"))) {
 
4566
                    hrc = attachToTapInterface(aNetworkAdapter);
 
4567
                    if (FAILED(hrc))
 
4568
                    {
 
4569
                        switch (hrc)
 
4570
                        {
 
4571
                            case VERR_ACCESS_DENIED:
 
4572
                                return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,  N_(
 
4573
                                                "Failed to open '/dev/%s' for read/write access.  Please check the "
 
4574
                                                "permissions of that node, and that the net.link.tap.user_open "
 
4575
                                                "sysctl is set.  Either run 'chmod 0666 /dev/%s' or "
 
4576
                                                "change the group of that node to vboxusers and make yourself "
 
4577
                                                "a member of that group.  Make sure that these changes are permanent."), pszBridgedIfName, pszBridgedIfName);
 
4578
                            default:
 
4579
                                AssertMsgFailed(("Could not attach to tap interface! Bad!\n"));
 
4580
                                return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
 
4581
                                                "Failed to initialize Host Interface Networking"));
 
4582
                        }
 
4583
                    }
 
4584
 
 
4585
                    Assert((int)maTapFD[uInstance] >= 0);
 
4586
                    if ((int)maTapFD[uInstance] >= 0)
 
4587
                    {
 
4588
                        InsertConfigString(pLunL0, "Driver", "HostInterface");
 
4589
                        InsertConfigNode(pLunL0, "Config", &pCfg);
 
4590
                        InsertConfigInteger(pCfg, "FileHandle", maTapFD[uInstance]);
 
4591
                    }
 
4592
                    break;
 
4593
                }
 
4594
#  endif
 
4595
                /** @todo Check for malformed names. */
 
4596
                const char *pszTrunk = pszBridgedIfName;
 
4597
 
 
4598
                /* Issue a warning if the interface is down */
 
4599
                {
 
4600
                    int iSock = socket(AF_INET, SOCK_DGRAM, 0);
 
4601
                    if (iSock >= 0)
 
4602
                    {
 
4603
                        struct ifreq Req;
 
4604
                        RT_ZERO(Req);
 
4605
                        RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pszBridgedIfName);
 
4606
                        if (ioctl(iSock, SIOCGIFFLAGS, &Req) >= 0)
 
4607
                            if ((Req.ifr_flags & IFF_UP) == 0)
 
4608
                                setVMRuntimeErrorCallbackF(0, "BridgedInterfaceDown",
 
4609
                                    N_("Bridged interface %s is down. Guest will not be able to use this interface"),
 
4610
                                    pszBridgedIfName);
 
4611
 
 
4612
                        close(iSock);
 
4613
                    }
 
4614
                }
 
4615
 
 
4616
# else
 
4617
#  error "PORTME (VBOX_WITH_NETFLT)"
 
4618
# endif
 
4619
 
 
4620
                InsertConfigString(pLunL0, "Driver", "IntNet");
 
4621
                InsertConfigNode(pLunL0, "Config", &pCfg);
 
4622
                InsertConfigString(pCfg, "Trunk", pszTrunk);
 
4623
                InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
 
4624
                InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure);
 
4625
                InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
 
4626
                char szNetwork[INTNET_MAX_NETWORK_NAME];
 
4627
 
 
4628
#if defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN)
 
4629
                /*
 
4630
                 * 'pszTrunk' contains just the interface name required in ring-0, while 'pszBridgedIfName' contains
 
4631
                 * interface name + optional description. We must not pass any description to the VM as it can differ
 
4632
                 * for the same interface name, eg: "nge0 - ethernet" (GUI) vs "nge0" (VBoxManage).
 
4633
                 */
 
4634
                RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszTrunk);
 
4635
#else
 
4636
                RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszBridgedIfName);
 
4637
#endif
 
4638
                InsertConfigString(pCfg, "Network", szNetwork);
 
4639
                networkName = Bstr(szNetwork);
 
4640
                trunkName = Bstr(pszTrunk);
 
4641
                trunkType = Bstr(TRUNKTYPE_NETFLT);
 
4642
 
 
4643
# if defined(RT_OS_DARWIN)
 
4644
                /** @todo Come up with a better deal here. Problem is that IHostNetworkInterface is completely useless here. */
 
4645
                if (    strstr(pszBridgedIfName, "Wireless")
 
4646
                    ||  strstr(pszBridgedIfName, "AirPort" ))
 
4647
                    InsertConfigInteger(pCfg, "SharedMacOnWire", true);
 
4648
# elif defined(RT_OS_LINUX)
 
4649
                int iSock = socket(AF_INET, SOCK_DGRAM, 0);
 
4650
                if (iSock >= 0)
 
4651
                {
 
4652
                    struct iwreq WRq;
 
4653
 
 
4654
                    RT_ZERO(WRq);
 
4655
                    strncpy(WRq.ifr_name, pszBridgedIfName, IFNAMSIZ);
 
4656
                    bool fSharedMacOnWire = ioctl(iSock, SIOCGIWNAME, &WRq) >= 0;
 
4657
                    close(iSock);
 
4658
                    if (fSharedMacOnWire)
 
4659
                    {
 
4660
                        InsertConfigInteger(pCfg, "SharedMacOnWire", true);
 
4661
                        Log(("Set SharedMacOnWire\n"));
 
4662
                    }
 
4663
                    else
 
4664
                        Log(("Failed to get wireless name\n"));
 
4665
                }
 
4666
                else
 
4667
                    Log(("Failed to open wireless socket\n"));
 
4668
# elif defined(RT_OS_FREEBSD)
 
4669
                int iSock = socket(AF_INET, SOCK_DGRAM, 0);
 
4670
                if (iSock >= 0)
 
4671
                {
 
4672
                    struct ieee80211req WReq;
 
4673
                    uint8_t abData[32];
 
4674
 
 
4675
                    RT_ZERO(WReq);
 
4676
                    strncpy(WReq.i_name, pszBridgedIfName, sizeof(WReq.i_name));
 
4677
                    WReq.i_type = IEEE80211_IOC_SSID;
 
4678
                    WReq.i_val = -1;
 
4679
                    WReq.i_data = abData;
 
4680
                    WReq.i_len = sizeof(abData);
 
4681
 
 
4682
                    bool fSharedMacOnWire = ioctl(iSock, SIOCG80211, &WReq) >= 0;
 
4683
                    close(iSock);
 
4684
                    if (fSharedMacOnWire)
 
4685
                    {
 
4686
                        InsertConfigInteger(pCfg, "SharedMacOnWire", true);
 
4687
                        Log(("Set SharedMacOnWire\n"));
 
4688
                    }
 
4689
                    else
 
4690
                        Log(("Failed to get wireless name\n"));
 
4691
                }
 
4692
                else
 
4693
                    Log(("Failed to open wireless socket\n"));
 
4694
# elif defined(RT_OS_WINDOWS)
 
4695
#  define DEVNAME_PREFIX L"\\\\.\\"
 
4696
                /* we are getting the medium type via IOCTL_NDIS_QUERY_GLOBAL_STATS Io Control
 
4697
                 * there is a pretty long way till there though since we need to obtain the symbolic link name
 
4698
                 * for the adapter device we are going to query given the device Guid */
 
4699
 
 
4700
 
 
4701
                /* prepend the "\\\\.\\" to the bind name to obtain the link name */
 
4702
 
 
4703
                wchar_t FileName[MAX_PATH];
 
4704
                wcscpy(FileName, DEVNAME_PREFIX);
 
4705
                wcscpy((wchar_t*)(((char*)FileName) + sizeof(DEVNAME_PREFIX) - sizeof(FileName[0])), pswzBindName);
 
4706
 
 
4707
                /* open the device */
 
4708
                HANDLE hDevice = CreateFile(FileName,
 
4709
                                            GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
 
4710
                                            NULL,
 
4711
                                            OPEN_EXISTING,
 
4712
                                            FILE_ATTRIBUTE_NORMAL,
 
4713
                                            NULL);
 
4714
 
 
4715
                if (hDevice != INVALID_HANDLE_VALUE)
 
4716
                {
 
4717
                    bool fSharedMacOnWire = false;
 
4718
 
 
4719
                    /* now issue the OID_GEN_PHYSICAL_MEDIUM query */
 
4720
                    DWORD Oid = OID_GEN_PHYSICAL_MEDIUM;
 
4721
                    NDIS_PHYSICAL_MEDIUM PhMedium;
 
4722
                    DWORD cbResult;
 
4723
                    if (DeviceIoControl(hDevice,
 
4724
                                        IOCTL_NDIS_QUERY_GLOBAL_STATS,
 
4725
                                        &Oid,
 
4726
                                        sizeof(Oid),
 
4727
                                        &PhMedium,
 
4728
                                        sizeof(PhMedium),
 
4729
                                        &cbResult,
 
4730
                                        NULL))
 
4731
                    {
 
4732
                        /* that was simple, now examine PhMedium */
 
4733
                        if (   PhMedium == NdisPhysicalMediumWirelessWan
 
4734
                            || PhMedium == NdisPhysicalMediumWirelessLan
 
4735
                            || PhMedium == NdisPhysicalMediumNative802_11
 
4736
                            || PhMedium == NdisPhysicalMediumBluetooth)
 
4737
                            fSharedMacOnWire = true;
 
4738
                    }
 
4739
                    else
 
4740
                    {
 
4741
                        int winEr = GetLastError();
 
4742
                        LogRel(("Console::configNetwork: DeviceIoControl failed, err (0x%x), ignoring\n", winEr));
 
4743
                        Assert(winEr == ERROR_INVALID_PARAMETER || winEr == ERROR_NOT_SUPPORTED || winEr == ERROR_BAD_COMMAND);
 
4744
                    }
 
4745
                    CloseHandle(hDevice);
 
4746
 
 
4747
                    if (fSharedMacOnWire)
 
4748
                    {
 
4749
                        Log(("this is a wireless adapter"));
 
4750
                        InsertConfigInteger(pCfg, "SharedMacOnWire", true);
 
4751
                        Log(("Set SharedMacOnWire\n"));
 
4752
                    }
 
4753
                    else
 
4754
                        Log(("this is NOT a wireless adapter"));
 
4755
                }
 
4756
                else
 
4757
                {
 
4758
                    int winEr = GetLastError();
 
4759
                    AssertLogRelMsgFailed(("Console::configNetwork: CreateFile failed, err (0x%x), ignoring\n", winEr));
 
4760
                }
 
4761
 
 
4762
                CoTaskMemFree(pswzBindName);
 
4763
 
 
4764
                pAdaptorComponent.setNull();
 
4765
                /* release the pNc finally */
 
4766
                VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
 
4767
# else
 
4768
                /** @todo PORTME: wireless detection */
 
4769
# endif
 
4770
 
 
4771
# if defined(RT_OS_SOLARIS)
 
4772
#  if 0 /* bird: this is a bit questionable and might cause more trouble than its worth.  */
 
4773
                /* Zone access restriction, don't allow snooping the global zone. */
 
4774
                zoneid_t ZoneId = getzoneid();
 
4775
                if (ZoneId != GLOBAL_ZONEID)
 
4776
                {
 
4777
                    InsertConfigInteger(pCfg, "IgnoreAllPromisc", true);
 
4778
                }
 
4779
#  endif
 
4780
# endif
 
4781
 
 
4782
#elif defined(RT_OS_WINDOWS) /* not defined NetFlt */
 
4783
            /* NOTHING TO DO HERE */
 
4784
#elif defined(RT_OS_LINUX)
 
4785
/// @todo aleksey: is there anything to be done here?
 
4786
#elif defined(RT_OS_FREEBSD)
 
4787
/** @todo FreeBSD: Check out this later (HIF networking). */
 
4788
#else
 
4789
# error "Port me"
 
4790
#endif
 
4791
                break;
 
4792
            }
 
4793
 
 
4794
            case NetworkAttachmentType_Internal:
 
4795
            {
 
4796
                hrc = aNetworkAdapter->COMGETTER(InternalNetwork)(bstr.asOutParam());       H();
 
4797
                if (!bstr.isEmpty())
 
4798
                {
 
4799
                    InsertConfigString(pLunL0, "Driver", "IntNet");
 
4800
                    InsertConfigNode(pLunL0, "Config", &pCfg);
 
4801
                    InsertConfigString(pCfg, "Network", bstr);
 
4802
                    InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
 
4803
                    InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
 
4804
                    networkName = bstr;
 
4805
                    trunkType = Bstr(TRUNKTYPE_WHATEVER);
 
4806
                }
 
4807
                break;
 
4808
            }
 
4809
 
 
4810
            case NetworkAttachmentType_HostOnly:
 
4811
            {
 
4812
                InsertConfigString(pLunL0, "Driver", "IntNet");
 
4813
                InsertConfigNode(pLunL0, "Config", &pCfg);
 
4814
 
 
4815
                Bstr HostOnlyName;
 
4816
                hrc = aNetworkAdapter->COMGETTER(HostOnlyInterface)(HostOnlyName.asOutParam());
 
4817
                if (FAILED(hrc))
 
4818
                {
 
4819
                    LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(HostOnlyInterface) failed, hrc (0x%x)\n", hrc));
 
4820
                    H();
 
4821
                }
 
4822
 
 
4823
                Utf8Str HostOnlyNameUtf8(HostOnlyName);
 
4824
                const char *pszHostOnlyName = HostOnlyNameUtf8.c_str();
 
4825
                ComPtr<IHostNetworkInterface> hostInterface;
 
4826
                rc = host->FindHostNetworkInterfaceByName(HostOnlyName.raw(),
 
4827
                                                          hostInterface.asOutParam());
 
4828
                if (!SUCCEEDED(rc))
 
4829
                {
 
4830
                    LogRel(("NetworkAttachmentType_HostOnly: FindByName failed, rc (0x%x)\n", rc));
 
4831
                    return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
 
4832
                                      N_("Nonexistent host networking interface, name '%ls'"),
 
4833
                                      HostOnlyName.raw());
 
4834
                }
 
4835
 
 
4836
                char szNetwork[INTNET_MAX_NETWORK_NAME];
 
4837
                RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszHostOnlyName);
 
4838
 
 
4839
#if defined(RT_OS_WINDOWS)
 
4840
# ifndef VBOX_WITH_NETFLT
 
4841
                hrc = E_NOTIMPL;
 
4842
                LogRel(("NetworkAttachmentType_HostOnly: Not Implemented\n"));
 
4843
                H();
 
4844
# else  /* defined VBOX_WITH_NETFLT*/
 
4845
                /** @todo r=bird: Put this in a function. */
 
4846
 
 
4847
                HostNetworkInterfaceType_T eIfType;
 
4848
                hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
 
4849
                if (FAILED(hrc))
 
4850
                {
 
4851
                    LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
 
4852
                    H();
 
4853
                }
 
4854
 
 
4855
                if (eIfType != HostNetworkInterfaceType_HostOnly)
 
4856
                    return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
 
4857
                                      N_("Interface ('%ls') is not a Host-Only Adapter interface"),
 
4858
                                      HostOnlyName.raw());
 
4859
 
 
4860
                hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
 
4861
                if (FAILED(hrc))
 
4862
                {
 
4863
                    LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
 
4864
                    H();
 
4865
                }
 
4866
                Guid hostIFGuid(bstr);
 
4867
 
 
4868
                INetCfg *pNc;
 
4869
                ComPtr<INetCfgComponent> pAdaptorComponent;
 
4870
                LPWSTR pszApp;
 
4871
                hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
 
4872
                Assert(hrc == S_OK);
 
4873
                if (hrc != S_OK)
 
4874
                {
 
4875
                    LogRel(("NetworkAttachmentType_HostOnly: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
 
4876
                    H();
 
4877
                }
 
4878
 
 
4879
                /* get the adapter's INetCfgComponent*/
 
4880
                hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(), pAdaptorComponent.asOutParam());
 
4881
                if (hrc != S_OK)
 
4882
                {
 
4883
                    VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
 
4884
                    LogRel(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n", hrc, hrc));
 
4885
                    H();
 
4886
                }
 
4887
#  define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
 
4888
                char szTrunkName[INTNET_MAX_TRUNK_NAME];
 
4889
                char *pszTrunkName = szTrunkName;
 
4890
                wchar_t * pswzBindName;
 
4891
                hrc = pAdaptorComponent->GetBindName(&pswzBindName);
 
4892
                Assert(hrc == S_OK);
 
4893
                if (hrc == S_OK)
 
4894
                {
 
4895
                    int cwBindName = (int)wcslen(pswzBindName) + 1;
 
4896
                    int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
 
4897
                    if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
 
4898
                    {
 
4899
                        strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
 
4900
                        pszTrunkName += cbFullBindNamePrefix-1;
 
4901
                        if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
 
4902
                                                sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
 
4903
                        {
 
4904
                            DWORD err = GetLastError();
 
4905
                            hrc = HRESULT_FROM_WIN32(err);
 
4906
                            AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n", hrc, hrc, err));
 
4907
                        }
 
4908
                    }
 
4909
                    else
 
4910
                    {
 
4911
                        AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: insufficient szTrunkName buffer space\n"));
 
4912
                        /** @todo set appropriate error code */
 
4913
                        hrc = E_FAIL;
 
4914
                    }
 
4915
 
 
4916
                    if (hrc != S_OK)
 
4917
                    {
 
4918
                        AssertFailed();
 
4919
                        CoTaskMemFree(pswzBindName);
 
4920
                        VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
 
4921
                        H();
 
4922
                    }
 
4923
                }
 
4924
                else
 
4925
                {
 
4926
                    VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
 
4927
                    AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n", hrc, hrc));
 
4928
                    H();
 
4929
                }
 
4930
 
 
4931
 
 
4932
                CoTaskMemFree(pswzBindName);
 
4933
 
 
4934
                pAdaptorComponent.setNull();
 
4935
                /* release the pNc finally */
 
4936
                VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
 
4937
 
 
4938
                const char *pszTrunk = szTrunkName;
 
4939
 
 
4940
                InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
 
4941
                InsertConfigString(pCfg, "Trunk", pszTrunk);
 
4942
                InsertConfigString(pCfg, "Network", szNetwork);
 
4943
                InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure); /** @todo why is this windows only?? */
 
4944
                networkName = Bstr(szNetwork);
 
4945
                trunkName   = Bstr(pszTrunk);
 
4946
                trunkType   = TRUNKTYPE_NETADP;
 
4947
# endif /* defined VBOX_WITH_NETFLT*/
 
4948
#elif defined(RT_OS_DARWIN)
 
4949
                InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
 
4950
                InsertConfigString(pCfg, "Network", szNetwork);
 
4951
                InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
 
4952
                networkName = Bstr(szNetwork);
 
4953
                trunkName   = Bstr(pszHostOnlyName);
 
4954
                trunkType   = TRUNKTYPE_NETADP;
 
4955
#else
 
4956
                InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
 
4957
                InsertConfigString(pCfg, "Network", szNetwork);
 
4958
                InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
 
4959
                networkName = Bstr(szNetwork);
 
4960
                trunkName   = Bstr(pszHostOnlyName);
 
4961
                trunkType   = TRUNKTYPE_NETFLT;
 
4962
#endif
 
4963
                InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
 
4964
 
 
4965
#if !defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
 
4966
 
 
4967
                Bstr tmpAddr, tmpMask;
 
4968
 
 
4969
                hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPAddress",
 
4970
                                                       pszHostOnlyName).raw(),
 
4971
                                               tmpAddr.asOutParam());
 
4972
                if (SUCCEEDED(hrc) && !tmpAddr.isEmpty())
 
4973
                {
 
4974
                    hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPNetMask",
 
4975
                                                           pszHostOnlyName).raw(),
 
4976
                                                   tmpMask.asOutParam());
 
4977
                    if (SUCCEEDED(hrc) && !tmpMask.isEmpty())
 
4978
                        hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
 
4979
                                                                  tmpMask.raw());
 
4980
                    else
 
4981
                        hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
 
4982
                                                                  Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
 
4983
                }
 
4984
                else
 
4985
                {
 
4986
                    /* Grab the IP number from the 'vboxnetX' instance number (see netif.h) */
 
4987
                    hrc = hostInterface->EnableStaticIPConfig(getDefaultIPv4Address(Bstr(pszHostOnlyName)).raw(),
 
4988
                                                              Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
 
4989
                }
 
4990
 
 
4991
                ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
 
4992
 
 
4993
                hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6Address",
 
4994
                                                       pszHostOnlyName).raw(),
 
4995
                                               tmpAddr.asOutParam());
 
4996
                if (SUCCEEDED(hrc))
 
4997
                    hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6NetMask", pszHostOnlyName).raw(),
 
4998
                                                   tmpMask.asOutParam());
 
4999
                if (SUCCEEDED(hrc) && !tmpAddr.isEmpty() && !tmpMask.isEmpty())
 
5000
                {
 
5001
                    hrc = hostInterface->EnableStaticIPConfigV6(tmpAddr.raw(),
 
5002
                                                                Utf8Str(tmpMask).toUInt32());
 
5003
                    ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
 
5004
                }
 
5005
#endif
 
5006
                break;
 
5007
            }
 
5008
 
 
5009
            case NetworkAttachmentType_Generic:
 
5010
            {
 
5011
                hrc = aNetworkAdapter->COMGETTER(GenericDriver)(bstr.asOutParam());         H();
 
5012
                SafeArray<BSTR> names;
 
5013
                SafeArray<BSTR> values;
 
5014
                hrc = aNetworkAdapter->GetProperties(Bstr().raw(),
 
5015
                                                     ComSafeArrayAsOutParam(names),
 
5016
                                                     ComSafeArrayAsOutParam(values));       H();
 
5017
 
 
5018
                InsertConfigString(pLunL0, "Driver", bstr);
 
5019
                InsertConfigNode(pLunL0, "Config", &pCfg);
 
5020
                for (size_t ii = 0; ii < names.size(); ++ii)
 
5021
                {
 
5022
                    if (values[ii] && *values[ii])
 
5023
                    {
 
5024
                        Utf8Str name = names[ii];
 
5025
                        Utf8Str value = values[ii];
 
5026
                        InsertConfigString(pCfg, name.c_str(), value);
 
5027
                    }
 
5028
                }
 
5029
                break;
 
5030
            }
 
5031
 
 
5032
            case NetworkAttachmentType_NATNetwork:
 
5033
            {
 
5034
                hrc = aNetworkAdapter->COMGETTER(NATNetwork)(bstr.asOutParam());            H();
 
5035
                if (!bstr.isEmpty())
 
5036
                {
 
5037
                    /** @todo add intnet prefix to separate namespaces, and add trunk if dealing with vboxnatX */
 
5038
                    InsertConfigString(pLunL0, "Driver", "IntNet");
 
5039
                    InsertConfigNode(pLunL0, "Config", &pCfg);
 
5040
                    InsertConfigString(pCfg, "Network", bstr);
 
5041
                    InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
 
5042
                    InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
 
5043
                    networkName = bstr;
 
5044
                    trunkType = Bstr(TRUNKTYPE_WHATEVER);
 
5045
                }
 
5046
                break;
 
5047
            }
 
5048
 
 
5049
            default:
 
5050
                AssertMsgFailed(("should not get here!\n"));
 
5051
                break;
 
5052
        }
 
5053
 
 
5054
        /*
 
5055
         * Attempt to attach the driver.
 
5056
         */
 
5057
        switch (eAttachmentType)
 
5058
        {
 
5059
            case NetworkAttachmentType_Null:
 
5060
                break;
 
5061
 
 
5062
            case NetworkAttachmentType_Bridged:
 
5063
            case NetworkAttachmentType_Internal:
 
5064
            case NetworkAttachmentType_HostOnly:
 
5065
            case NetworkAttachmentType_NAT:
 
5066
            case NetworkAttachmentType_Generic:
 
5067
            case NetworkAttachmentType_NATNetwork:
 
5068
            {
 
5069
                if (SUCCEEDED(hrc) && SUCCEEDED(rc))
 
5070
                {
 
5071
                    if (fAttachDetach)
 
5072
                    {
 
5073
                        rc = PDMR3DriverAttach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/, NULL /* ppBase */);
 
5074
                        //AssertRC(rc);
 
5075
                    }
 
5076
 
 
5077
                    {
 
5078
                        /** @todo pritesh: get the dhcp server name from the
 
5079
                         * previous network configuration and then stop the server
 
5080
                         * else it may conflict with the dhcp server running  with
 
5081
                         * the current attachment type
 
5082
                         */
 
5083
                        /* Stop the hostonly DHCP Server */
 
5084
                    }
 
5085
 
 
5086
                    /*
 
5087
                     * NAT networks start their DHCP server theirself, see NATNetwork::Start()
 
5088
                     */
 
5089
                    if (   !networkName.isEmpty()
 
5090
                        && eAttachmentType != NetworkAttachmentType_NATNetwork)
 
5091
                    {
 
5092
                        /*
 
5093
                         * Until we implement service reference counters DHCP Server will be stopped
 
5094
                         * by DHCPServerRunner destructor.
 
5095
                         */
 
5096
                        ComPtr<IDHCPServer> dhcpServer;
 
5097
                        hrc = virtualBox->FindDHCPServerByNetworkName(networkName.raw(),
 
5098
                                                                      dhcpServer.asOutParam());
 
5099
                        if (SUCCEEDED(hrc))
 
5100
                        {
 
5101
                            /* there is a DHCP server available for this network */
 
5102
                            BOOL fEnabledDhcp;
 
5103
                            hrc = dhcpServer->COMGETTER(Enabled)(&fEnabledDhcp);
 
5104
                            if (FAILED(hrc))
 
5105
                            {
 
5106
                                LogRel(("DHCP svr: COMGETTER(Enabled) failed, hrc (%Rhrc)\n", hrc));
 
5107
                                H();
 
5108
                            }
 
5109
 
 
5110
                            if (fEnabledDhcp)
 
5111
                                hrc = dhcpServer->Start(networkName.raw(),
 
5112
                                                        trunkName.raw(),
 
5113
                                                        trunkType.raw());
 
5114
                        }
 
5115
                        else
 
5116
                            hrc = S_OK;
 
5117
                    }
 
5118
                }
 
5119
 
 
5120
                break;
 
5121
            }
 
5122
 
 
5123
            default:
 
5124
                AssertMsgFailed(("should not get here!\n"));
 
5125
                break;
 
5126
        }
 
5127
 
 
5128
        meAttachmentType[uInstance] = eAttachmentType;
 
5129
    }
 
5130
    catch (ConfigError &x)
 
5131
    {
 
5132
        // InsertConfig threw something:
 
5133
        return x.m_vrc;
 
5134
    }
 
5135
 
 
5136
#undef H
 
5137
 
 
5138
    return VINF_SUCCESS;
 
5139
}
 
5140
 
 
5141
#ifdef VBOX_WITH_GUEST_PROPS
 
5142
/**
 
5143
 * Set an array of guest properties
 
5144
 */
 
5145
static void configSetProperties(VMMDev * const pVMMDev,
 
5146
                                void *names,
 
5147
                                void *values,
 
5148
                                void *timestamps,
 
5149
                                void *flags)
 
5150
{
 
5151
    VBOXHGCMSVCPARM parms[4];
 
5152
 
 
5153
    parms[0].type = VBOX_HGCM_SVC_PARM_PTR;
 
5154
    parms[0].u.pointer.addr = names;
 
5155
    parms[0].u.pointer.size = 0;  /* We don't actually care. */
 
5156
    parms[1].type = VBOX_HGCM_SVC_PARM_PTR;
 
5157
    parms[1].u.pointer.addr = values;
 
5158
    parms[1].u.pointer.size = 0;  /* We don't actually care. */
 
5159
    parms[2].type = VBOX_HGCM_SVC_PARM_PTR;
 
5160
    parms[2].u.pointer.addr = timestamps;
 
5161
    parms[2].u.pointer.size = 0;  /* We don't actually care. */
 
5162
    parms[3].type = VBOX_HGCM_SVC_PARM_PTR;
 
5163
    parms[3].u.pointer.addr = flags;
 
5164
    parms[3].u.pointer.size = 0;  /* We don't actually care. */
 
5165
 
 
5166
    pVMMDev->hgcmHostCall("VBoxGuestPropSvc",
 
5167
                          guestProp::SET_PROPS_HOST,
 
5168
                          4,
 
5169
                          &parms[0]);
 
5170
}
 
5171
 
 
5172
/**
 
5173
 * Set a single guest property
 
5174
 */
 
5175
static void configSetProperty(VMMDev * const pVMMDev,
 
5176
                              const char *pszName,
 
5177
                              const char *pszValue,
 
5178
                              const char *pszFlags)
 
5179
{
 
5180
    VBOXHGCMSVCPARM parms[4];
 
5181
 
 
5182
    AssertPtrReturnVoid(pszName);
 
5183
    AssertPtrReturnVoid(pszValue);
 
5184
    AssertPtrReturnVoid(pszFlags);
 
5185
    parms[0].type = VBOX_HGCM_SVC_PARM_PTR;
 
5186
    parms[0].u.pointer.addr = (void *)pszName;
 
5187
    parms[0].u.pointer.size = (uint32_t)strlen(pszName) + 1;
 
5188
    parms[1].type = VBOX_HGCM_SVC_PARM_PTR;
 
5189
    parms[1].u.pointer.addr = (void *)pszValue;
 
5190
    parms[1].u.pointer.size = (uint32_t)strlen(pszValue) + 1;
 
5191
    parms[2].type = VBOX_HGCM_SVC_PARM_PTR;
 
5192
    parms[2].u.pointer.addr = (void *)pszFlags;
 
5193
    parms[2].u.pointer.size = (uint32_t)strlen(pszFlags) + 1;
 
5194
    pVMMDev->hgcmHostCall("VBoxGuestPropSvc", guestProp::SET_PROP_HOST, 3,
 
5195
                          &parms[0]);
 
5196
}
 
5197
 
 
5198
/**
 
5199
 * Set the global flags value by calling the service
 
5200
 * @returns the status returned by the call to the service
 
5201
 *
 
5202
 * @param   pTable  the service instance handle
 
5203
 * @param   eFlags  the flags to set
 
5204
 */
 
5205
int configSetGlobalPropertyFlags(VMMDev * const pVMMDev,
 
5206
                                 guestProp::ePropFlags eFlags)
 
5207
{
 
5208
    VBOXHGCMSVCPARM paParm;
 
5209
    paParm.setUInt32(eFlags);
 
5210
    int rc = pVMMDev->hgcmHostCall("VBoxGuestPropSvc",
 
5211
                                   guestProp::SET_GLOBAL_FLAGS_HOST, 1,
 
5212
                                   &paParm);
 
5213
    if (RT_FAILURE(rc))
 
5214
    {
 
5215
        char szFlags[guestProp::MAX_FLAGS_LEN];
 
5216
        if (RT_FAILURE(writeFlags(eFlags, szFlags)))
 
5217
            Log(("Failed to set the global flags.\n"));
 
5218
        else
 
5219
            Log(("Failed to set the global flags \"%s\".\n", szFlags));
 
5220
    }
 
5221
    return rc;
 
5222
}
 
5223
#endif /* VBOX_WITH_GUEST_PROPS */
 
5224
 
 
5225
/**
 
5226
 * Set up the Guest Property service, populate it with properties read from
 
5227
 * the machine XML and set a couple of initial properties.
 
5228
 */
 
5229
/* static */ int Console::configGuestProperties(void *pvConsole, PUVM pUVM)
 
5230
{
 
5231
#ifdef VBOX_WITH_GUEST_PROPS
 
5232
    AssertReturn(pvConsole, VERR_INVALID_POINTER);
 
5233
    ComObjPtr<Console> pConsole = static_cast<Console *>(pvConsole);
 
5234
    AssertReturn(pConsole->m_pVMMDev, VERR_INVALID_POINTER);
 
5235
 
 
5236
    /* Load the service */
 
5237
    int rc = pConsole->m_pVMMDev->hgcmLoadService("VBoxGuestPropSvc", "VBoxGuestPropSvc");
 
5238
 
 
5239
    if (RT_FAILURE(rc))
 
5240
    {
 
5241
        LogRel(("VBoxGuestPropSvc is not available. rc = %Rrc\n", rc));
 
5242
        /* That is not a fatal failure. */
 
5243
        rc = VINF_SUCCESS;
 
5244
    }
 
5245
    else
 
5246
    {
 
5247
        /*
 
5248
         * Initialize built-in properties that can be changed and saved.
 
5249
         *
 
5250
         * These are typically transient properties that the guest cannot
 
5251
         * change.
 
5252
         */
 
5253
 
 
5254
        {
 
5255
            VBOXHGCMSVCPARM Params[2];
 
5256
            int rc2 = pConsole->m_pVMMDev->hgcmHostCall("VBoxGuestPropSvc", guestProp::GET_DBGF_INFO_FN, 2, &Params[0]);
 
5257
            if (RT_SUCCESS(rc2))
 
5258
            {
 
5259
                PFNDBGFHANDLEREXT pfnHandler = (PFNDBGFHANDLEREXT)(uintptr_t)Params[0].u.pointer.addr;
 
5260
                void *pService = (void*)Params[1].u.pointer.addr;
 
5261
                DBGFR3InfoRegisterExternal(pUVM, "guestprops", "Display the guest properties", pfnHandler, pService);
 
5262
            }
 
5263
        }
 
5264
 
 
5265
        /* Sysprep execution by VBoxService. */
 
5266
        configSetProperty(pConsole->m_pVMMDev,
 
5267
                          "/VirtualBox/HostGuest/SysprepExec", "",
 
5268
                          "TRANSIENT, RDONLYGUEST");
 
5269
        configSetProperty(pConsole->m_pVMMDev,
 
5270
                          "/VirtualBox/HostGuest/SysprepArgs", "",
 
5271
                          "TRANSIENT, RDONLYGUEST");
 
5272
 
 
5273
        /*
 
5274
         * Pull over the properties from the server.
 
5275
         */
 
5276
        SafeArray<BSTR> namesOut;
 
5277
        SafeArray<BSTR> valuesOut;
 
5278
        SafeArray<LONG64> timestampsOut;
 
5279
        SafeArray<BSTR> flagsOut;
 
5280
        HRESULT hrc;
 
5281
        hrc = pConsole->mControl->PullGuestProperties(ComSafeArrayAsOutParam(namesOut),
 
5282
                                                      ComSafeArrayAsOutParam(valuesOut),
 
5283
                                                      ComSafeArrayAsOutParam(timestampsOut),
 
5284
                                                      ComSafeArrayAsOutParam(flagsOut));
 
5285
        AssertLogRelMsgReturn(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
 
5286
        size_t cProps = namesOut.size();
 
5287
        size_t cAlloc = cProps + 1;
 
5288
        if (   valuesOut.size() != cProps
 
5289
            || timestampsOut.size() != cProps
 
5290
            || flagsOut.size() != cProps
 
5291
           )
 
5292
            AssertFailedReturn(VERR_INVALID_PARAMETER);
 
5293
 
 
5294
        char **papszNames, **papszValues, **papszFlags;
 
5295
        char szEmpty[] = "";
 
5296
        LONG64 *pai64Timestamps;
 
5297
        papszNames = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
 
5298
        papszValues = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
 
5299
        pai64Timestamps = (LONG64 *)RTMemTmpAllocZ(sizeof(LONG64) * cAlloc);
 
5300
        papszFlags = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
 
5301
        if (papszNames && papszValues && pai64Timestamps && papszFlags)
 
5302
        {
 
5303
            for (unsigned i = 0; RT_SUCCESS(rc) && i < cProps; ++i)
 
5304
            {
 
5305
                AssertPtrReturn(namesOut[i], VERR_INVALID_PARAMETER);
 
5306
                rc = RTUtf16ToUtf8(namesOut[i], &papszNames[i]);
 
5307
                if (RT_FAILURE(rc))
 
5308
                    break;
 
5309
                if (valuesOut[i])
 
5310
                    rc = RTUtf16ToUtf8(valuesOut[i], &papszValues[i]);
 
5311
                else
 
5312
                    papszValues[i] = szEmpty;
 
5313
                if (RT_FAILURE(rc))
 
5314
                    break;
 
5315
                pai64Timestamps[i] = timestampsOut[i];
 
5316
                if (flagsOut[i])
 
5317
                    rc = RTUtf16ToUtf8(flagsOut[i], &papszFlags[i]);
 
5318
                else
 
5319
                    papszFlags[i] = szEmpty;
 
5320
            }
 
5321
            if (RT_SUCCESS(rc))
 
5322
                configSetProperties(pConsole->m_pVMMDev,
 
5323
                                    (void *)papszNames,
 
5324
                                    (void *)papszValues,
 
5325
                                    (void *)pai64Timestamps,
 
5326
                                    (void *)papszFlags);
 
5327
            for (unsigned i = 0; i < cProps; ++i)
 
5328
            {
 
5329
                RTStrFree(papszNames[i]);
 
5330
                if (valuesOut[i])
 
5331
                    RTStrFree(papszValues[i]);
 
5332
                if (flagsOut[i])
 
5333
                    RTStrFree(papszFlags[i]);
 
5334
            }
 
5335
        }
 
5336
        else
 
5337
            rc = VERR_NO_MEMORY;
 
5338
        RTMemTmpFree(papszNames);
 
5339
        RTMemTmpFree(papszValues);
 
5340
        RTMemTmpFree(pai64Timestamps);
 
5341
        RTMemTmpFree(papszFlags);
 
5342
        AssertRCReturn(rc, rc);
 
5343
 
 
5344
        /*
 
5345
         * These properties have to be set before pulling over the properties
 
5346
         * from the machine XML, to ensure that properties saved in the XML
 
5347
         * will override them.
 
5348
         */
 
5349
        /* Set the raw VBox version string as a guest property. Used for host/guest
 
5350
         * version comparison. */
 
5351
        configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxVer",
 
5352
                          VBOX_VERSION_STRING_RAW, "TRANSIENT, RDONLYGUEST");
 
5353
        /* Set the full VBox version string as a guest property. Can contain vendor-specific
 
5354
         * information/branding and/or pre-release tags. */
 
5355
        configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxVerExt",
 
5356
                          VBOX_VERSION_STRING, "TRANSIENT, RDONLYGUEST");
 
5357
        /* Set the VBox SVN revision as a guest property */
 
5358
        configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxRev",
 
5359
                          RTBldCfgRevisionStr(), "TRANSIENT, RDONLYGUEST");
 
5360
 
 
5361
        /*
 
5362
         * Register the host notification callback
 
5363
         */
 
5364
        HGCMSVCEXTHANDLE hDummy;
 
5365
        HGCMHostRegisterServiceExtension(&hDummy, "VBoxGuestPropSvc",
 
5366
                                         Console::doGuestPropNotification,
 
5367
                                         pvConsole);
 
5368
 
 
5369
#ifdef VBOX_WITH_GUEST_PROPS_RDONLY_GUEST
 
5370
        rc = configSetGlobalPropertyFlags(pConsole->m_pVMMDev,
 
5371
                                          guestProp::RDONLYGUEST);
 
5372
        AssertRCReturn(rc, rc);
 
5373
#endif
 
5374
 
 
5375
        Log(("Set VBoxGuestPropSvc property store\n"));
 
5376
    }
 
5377
    return VINF_SUCCESS;
 
5378
#else /* !VBOX_WITH_GUEST_PROPS */
 
5379
    return VERR_NOT_SUPPORTED;
 
5380
#endif /* !VBOX_WITH_GUEST_PROPS */
 
5381
}
 
5382
 
 
5383
/**
 
5384
 * Set up the Guest Control service.
 
5385
 */
 
5386
/* static */ int Console::configGuestControl(void *pvConsole)
 
5387
{
 
5388
#ifdef VBOX_WITH_GUEST_CONTROL
 
5389
    AssertReturn(pvConsole, VERR_INVALID_POINTER);
 
5390
    ComObjPtr<Console> pConsole = static_cast<Console *>(pvConsole);
 
5391
 
 
5392
    /* Load the service */
 
5393
    int rc = pConsole->m_pVMMDev->hgcmLoadService("VBoxGuestControlSvc", "VBoxGuestControlSvc");
 
5394
 
 
5395
    if (RT_FAILURE(rc))
 
5396
    {
 
5397
        LogRel(("VBoxGuestControlSvc is not available. rc = %Rrc\n", rc));
 
5398
        /* That is not a fatal failure. */
 
5399
        rc = VINF_SUCCESS;
 
5400
    }
 
5401
    else
 
5402
    {
 
5403
        HGCMSVCEXTHANDLE hDummy;
 
5404
        rc = HGCMHostRegisterServiceExtension(&hDummy, "VBoxGuestControlSvc",
 
5405
                                              &Guest::notifyCtrlDispatcher,
 
5406
                                              pConsole->getGuest());
 
5407
        if (RT_FAILURE(rc))
 
5408
            Log(("Cannot register VBoxGuestControlSvc extension!\n"));
 
5409
        else
 
5410
            Log(("VBoxGuestControlSvc loaded\n"));
 
5411
    }
 
5412
 
 
5413
    return rc;
 
5414
#else /* !VBOX_WITH_GUEST_CONTROL */
 
5415
    return VERR_NOT_SUPPORTED;
 
5416
#endif /* !VBOX_WITH_GUEST_CONTROL */
 
5417
}