VirtualBox

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

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

warning

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