VirtualBox

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

Last change on this file since 49983 was 49983, checked in by vboxsync, 11 years ago

Devices/Graphics: VMware SVGA II compatible graphics emulation (2D only), including the associated small API and VBoxManage changes, contributed by trivirt AG.

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

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