VirtualBox

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

Last change on this file since 92154 was 92135, checked in by vboxsync, 3 years ago

Main/Console: Fix long standing incorrect error code check in code path which is not enabled by default (VBOX_WITH_NETFLT not defined on Linux).

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

© 2023 Oracle
ContactPrivacy policyTerms of Use