VirtualBox

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

Last change on this file since 53877 was 53831, checked in by vboxsync, 10 years ago

PDM/Audio: Build fix; forgot some files.

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