VirtualBox

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

Last change on this file since 55358 was 55314, checked in by vboxsync, 10 years ago

Main/Console: report installed driver versions to VM release log

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

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