VirtualBox

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

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

build fix: perhaps we need guardian to split class NetworkServiceRunner from macro definitions TRUNKTYPE_*.
(clang unfortunatly doesn't catch such cases)

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

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