VirtualBox

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

Last change on this file since 57552 was 57552, checked in by vboxsync, 9 years ago

Main: be slightly more descriptive with this informational message

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

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