VirtualBox

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

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

Main: Configure the hotplug flag for the SATA controllers always, not only when the BIOS is present

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