VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp@ 57808

最後變更 在這個檔案從57808是 57808,由 vboxsync 提交於 10 年 前

Installer/linux and tinderclient: use Qt from build server for RPM builds - changed the wrong line in tinderclient.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette