VirtualBox

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

Last change on this file since 42162 was 41925, checked in by vboxsync, 13 years ago

allow to change the clipboard mode during runtime (API change including 'VBoxManage controlvm' change)

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