VirtualBox

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

Last change on this file since 60999 was 60743, checked in by vboxsync, 9 years ago

Main/ConsoleImpl2: Recognize 'enabled=0' as a valid paravirtdebug option for Hyper-V, don't fail VM startup.

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

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