VirtualBox

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

Last change on this file since 92404 was 92366, checked in by vboxsync, 3 years ago

Audio/Validation Kit: More verbosity level handling for the testdriver + Main side, take 2. bugref:10008

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 280.1 KB
Line 
1/* $Id: ConsoleImpl2.cpp 92366 2021-11-11 13:00: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_audio.e.l.l2.l3.f"
3290 " audio_mixer.e.l.l2.l3.f"
3291 " dev_hda_codec.e.l.l2.l3.f"
3292 " dev_hda.e.l.l2.l3.f"
3293 " dev_ac97.e.l.l2.l3.f"
3294 " dev_sb16.e.l.l2.l3.f");
3295
3296 LogRel(("Audio: Debug level set to %RU32\n", uDebugLevel));
3297
3298 switch (uDebugLevel)
3299 {
3300 case 0:
3301 strGroups += " drv_host_audio.e.l.l2.l3.f";
3302 break;
3303 case 1:
3304 RT_FALL_THROUGH();
3305 case 2:
3306 RT_FALL_THROUGH();
3307 case 3:
3308 strGroups += " drv_host_audio.e.l.l2.l3.f+audio_test.e.l.l2.l3.f";
3309 break;
3310 case 4:
3311 RT_FALL_THROUGH();
3312 default:
3313 strGroups += " drv_host_audio.e.l.l2.l3.l4.f+audio_test.e.l.l2.l3.l4.f";
3314 break;
3315 }
3316
3317 rc = RTLogGroupSettings(RTLogRelGetDefaultInstance(), strGroups.c_str());
3318 if (RT_FAILURE(rc))
3319 LogRel(("Audio: Setting debug logging failed, rc=%Rrc\n", rc));
3320 }
3321 }
3322
3323#ifdef VBOX_WITH_SHARED_CLIPBOARD
3324 /*
3325 * Shared Clipboard.
3326 */
3327 {
3328 ClipboardMode_T enmClipboardMode = ClipboardMode_Disabled;
3329 hrc = pMachine->COMGETTER(ClipboardMode)(&enmClipboardMode); H();
3330# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
3331 BOOL fFileTransfersEnabled;
3332 hrc = pMachine->COMGETTER(ClipboardFileTransfersEnabled)(&fFileTransfersEnabled); H();
3333#endif
3334
3335 /* Load the service */
3336 rc = pVMMDev->hgcmLoadService("VBoxSharedClipboard", "VBoxSharedClipboard");
3337 if (RT_SUCCESS(rc))
3338 {
3339 LogRel(("Shared Clipboard: Service loaded\n"));
3340
3341 /* Set initial clipboard mode. */
3342 rc = i_changeClipboardMode(enmClipboardMode);
3343 AssertLogRelMsg(RT_SUCCESS(rc), ("Shared Clipboard: Failed to set initial clipboard mode (%d): rc=%Rrc\n",
3344 enmClipboardMode, rc));
3345
3346 /* Setup the service. */
3347 VBOXHGCMSVCPARM parm;
3348 HGCMSvcSetU32(&parm, !i_useHostClipboard());
3349 rc = pVMMDev->hgcmHostCall("VBoxSharedClipboard", VBOX_SHCL_HOST_FN_SET_HEADLESS, 1, &parm);
3350 AssertLogRelMsg(RT_SUCCESS(rc), ("Shared Clipboard: Failed to set initial headless mode (%RTbool): rc=%Rrc\n",
3351 !i_useHostClipboard(), rc));
3352
3353# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
3354 rc = i_changeClipboardFileTransferMode(RT_BOOL(fFileTransfersEnabled));
3355 AssertLogRelMsg(RT_SUCCESS(rc), ("Shared Clipboard: Failed to set initial file transfers mode (%u): rc=%Rrc\n",
3356 fFileTransfersEnabled, rc));
3357
3358 /** @todo Register area callbacks? (See also deregistration todo in Console::i_powerDown.) */
3359# endif
3360 }
3361 else
3362 LogRel(("Shared Clipboard: Not available, rc=%Rrc\n", rc));
3363 rc = VINF_SUCCESS; /* None of the potential failures above are fatal. */
3364 }
3365#endif /* VBOX_WITH_SHARED_CLIPBOARD */
3366
3367 /*
3368 * HGCM HostChannel.
3369 */
3370 {
3371 Bstr value;
3372 hrc = pMachine->GetExtraData(Bstr("HGCM/HostChannel").raw(),
3373 value.asOutParam());
3374
3375 if ( hrc == S_OK
3376 && value == "1")
3377 {
3378 rc = pVMMDev->hgcmLoadService("VBoxHostChannel", "VBoxHostChannel");
3379 if (RT_FAILURE(rc))
3380 {
3381 LogRel(("VBoxHostChannel is not available, rc=%Rrc\n", rc));
3382 /* That is not a fatal failure. */
3383 rc = VINF_SUCCESS;
3384 }
3385 }
3386 }
3387
3388#ifdef VBOX_WITH_DRAG_AND_DROP
3389 /*
3390 * Drag and Drop.
3391 */
3392 {
3393 DnDMode_T enmMode = DnDMode_Disabled;
3394 hrc = pMachine->COMGETTER(DnDMode)(&enmMode); H();
3395
3396 /* Load the service */
3397 rc = pVMMDev->hgcmLoadService("VBoxDragAndDropSvc", "VBoxDragAndDropSvc");
3398 if (RT_FAILURE(rc))
3399 {
3400 LogRel(("Drag and drop service is not available, rc=%Rrc\n", rc));
3401 /* That is not a fatal failure. */
3402 rc = VINF_SUCCESS;
3403 }
3404 else
3405 {
3406 rc = HGCMHostRegisterServiceExtension(&m_hHgcmSvcExtDragAndDrop, "VBoxDragAndDropSvc",
3407 &GuestDnD::notifyDnDDispatcher,
3408 GuestDnDInst());
3409 if (RT_FAILURE(rc))
3410 Log(("Cannot register VBoxDragAndDropSvc extension, rc=%Rrc\n", rc));
3411 else
3412 {
3413 LogRel(("Drag and drop service loaded\n"));
3414 rc = i_changeDnDMode(enmMode);
3415 }
3416 }
3417 }
3418#endif /* VBOX_WITH_DRAG_AND_DROP */
3419
3420#if defined(VBOX_WITH_TPM)
3421 /*
3422 * Configure the Trusted Platform Module.
3423 */
3424 ComObjPtr<ITrustedPlatformModule> ptrTpm;
3425 TpmType_T enmTpmType = TpmType_None;
3426
3427 hrc = pMachine->COMGETTER(TrustedPlatformModule)(ptrTpm.asOutParam()); H();
3428 hrc = ptrTpm->COMGETTER(Type)(&enmTpmType); H();
3429 if (enmTpmType != TpmType_None)
3430 {
3431 InsertConfigNode(pDevices, "tpm", &pDev);
3432 InsertConfigNode(pDev, "0", &pInst);
3433 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3434 InsertConfigNode(pInst, "Config", &pCfg);
3435 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3436
3437 switch (enmTpmType)
3438 {
3439 case TpmType_v1_2:
3440 case TpmType_v2_0:
3441 {
3442 InsertConfigString(pLunL0, "Driver", "TpmEmuTpms");
3443 InsertConfigNode(pLunL0, "Config", &pCfg);
3444 InsertConfigInteger(pCfg, "TpmVersion", enmTpmType == TpmType_v1_2 ? 1 : 2);
3445 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
3446 InsertConfigString(pLunL1, "Driver", "NvramStore");
3447 break;
3448 }
3449 case TpmType_Host:
3450 {
3451#if defined(RT_OS_LINUX) || defined(RT_OS_WINDOWS)
3452 InsertConfigString(pLunL0, "Driver", "TpmHost");
3453 InsertConfigNode(pLunL0, "Config", &pCfg);
3454#endif
3455 break;
3456 }
3457 case TpmType_Swtpm:
3458 {
3459 Bstr location;
3460 hrc = ptrTpm->COMGETTER(Location)(location.asOutParam()); H();
3461
3462 InsertConfigString(pLunL0, "Driver", "TpmEmu");
3463 InsertConfigNode(pLunL0, "Config", &pCfg);
3464 InsertConfigString(pCfg, "Location", location);
3465 break;
3466 }
3467 default:
3468 AssertFailedBreak();
3469 }
3470 }
3471#endif
3472
3473 /*
3474 * ACPI
3475 */
3476 BOOL fACPI;
3477 hrc = biosSettings->COMGETTER(ACPIEnabled)(&fACPI); H();
3478 if (fACPI)
3479 {
3480 /* Always show the CPU leafs when we have multiple VCPUs or when the IO-APIC is enabled.
3481 * The Windows SMP kernel needs a CPU leaf or else its idle loop will burn cpu cycles; the
3482 * intelppm driver refuses to register an idle state handler.
3483 * Always show CPU leafs for OS X guests. */
3484 BOOL fShowCpu = fOsXGuest;
3485 if (cCpus > 1 || fIOAPIC)
3486 fShowCpu = true;
3487
3488 BOOL fCpuHotPlug;
3489 hrc = pMachine->COMGETTER(CPUHotPlugEnabled)(&fCpuHotPlug); H();
3490
3491 InsertConfigNode(pDevices, "acpi", &pDev);
3492 InsertConfigNode(pDev, "0", &pInst);
3493 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3494 InsertConfigNode(pInst, "Config", &pCfg);
3495 hrc = pBusMgr->assignPCIDevice("acpi", pInst); H();
3496
3497 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
3498
3499 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
3500 InsertConfigInteger(pCfg, "FdcEnabled", fFdcEnabled);
3501 InsertConfigInteger(pCfg, "HpetEnabled", fHPETEnabled);
3502 InsertConfigInteger(pCfg, "SmcEnabled", fSmcEnabled);
3503 InsertConfigInteger(pCfg, "ShowRtc", fShowRtc);
3504 if (fOsXGuest && !llBootNics.empty())
3505 {
3506 BootNic aNic = llBootNics.front();
3507 uint32_t u32NicPCIAddr = (aNic.mPCIAddress.miDevice << 16) | aNic.mPCIAddress.miFn;
3508 InsertConfigInteger(pCfg, "NicPciAddress", u32NicPCIAddr);
3509 }
3510 if (fOsXGuest && fAudioEnabled)
3511 {
3512 PCIBusAddress Address;
3513 if (pBusMgr->findPCIAddress("hda", 0, Address))
3514 {
3515 uint32_t u32AudioPCIAddr = (Address.miDevice << 16) | Address.miFn;
3516 InsertConfigInteger(pCfg, "AudioPciAddress", u32AudioPCIAddr);
3517 }
3518 }
3519 if (fOsXGuest)
3520 {
3521 PCIBusAddress Address;
3522 if (pBusMgr->findPCIAddress("nvme", 0, Address))
3523 {
3524 uint32_t u32NvmePCIAddr = (Address.miDevice << 16) | Address.miFn;
3525 InsertConfigInteger(pCfg, "NvmePciAddress", u32NvmePCIAddr);
3526 }
3527 }
3528 if (iommuType == IommuType_AMD)
3529 {
3530 PCIBusAddress Address;
3531 if (pBusMgr->findPCIAddress("iommu-amd", 0, Address))
3532 {
3533 uint32_t u32IommuAddress = (Address.miDevice << 16) | Address.miFn;
3534 InsertConfigInteger(pCfg, "IommuAmdEnabled", true);
3535 InsertConfigInteger(pCfg, "IommuPciAddress", u32IommuAddress);
3536 if (pBusMgr->findPCIAddress("sb-ioapic", 0, Address))
3537 {
3538 uint32_t const u32SbIoapicAddress = (Address.miDevice << 16) | Address.miFn;
3539 InsertConfigInteger(pCfg, "SbIoApicPciAddress", u32SbIoapicAddress);
3540 }
3541 else
3542 return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
3543 N_("AMD IOMMU is enabled, but the I/O APIC is not assigned a PCI address!"));
3544 }
3545 }
3546 else if (iommuType == IommuType_Intel)
3547 {
3548 PCIBusAddress Address;
3549 if (pBusMgr->findPCIAddress("iommu-intel", 0, Address))
3550 {
3551 uint32_t u32IommuAddress = (Address.miDevice << 16) | Address.miFn;
3552 InsertConfigInteger(pCfg, "IommuIntelEnabled", true);
3553 InsertConfigInteger(pCfg, "IommuPciAddress", u32IommuAddress);
3554 if (pBusMgr->findPCIAddress("sb-ioapic", 0, Address))
3555 {
3556 uint32_t const u32SbIoapicAddress = (Address.miDevice << 16) | Address.miFn;
3557 InsertConfigInteger(pCfg, "SbIoApicPciAddress", u32SbIoapicAddress);
3558 }
3559 else
3560 return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
3561 N_("Intel IOMMU is enabled, but the I/O APIC is not assigned a PCI address!"));
3562 }
3563 }
3564
3565 InsertConfigInteger(pCfg, "IocPciAddress", uIocPCIAddress);
3566 if (chipsetType == ChipsetType_ICH9)
3567 {
3568 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
3569 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
3570 /* 64-bit prefetch window root resource:
3571 * Only for ICH9 and if PAE or Long Mode is enabled.
3572 * And only with hardware virtualization (@bugref{5454}). */
3573 if ( (fEnablePAE || fIsGuest64Bit)
3574 && fSupportsHwVirtEx /* HwVirt needs to be supported by the host
3575 otherwise VMM falls back to raw mode */
3576 && fHMEnabled /* HwVirt needs to be enabled in VM config */)
3577 InsertConfigInteger(pCfg, "PciPref64Enabled", 1);
3578 }
3579 InsertConfigInteger(pCfg, "HostBusPciAddress", uHbcPCIAddress);
3580 InsertConfigInteger(pCfg, "ShowCpu", fShowCpu);
3581 InsertConfigInteger(pCfg, "CpuHotPlug", fCpuHotPlug);
3582
3583 InsertConfigInteger(pCfg, "Serial0IoPortBase", auSerialIoPortBase[0]);
3584 InsertConfigInteger(pCfg, "Serial0Irq", auSerialIrq[0]);
3585
3586 InsertConfigInteger(pCfg, "Serial1IoPortBase", auSerialIoPortBase[1]);
3587 InsertConfigInteger(pCfg, "Serial1Irq", auSerialIrq[1]);
3588
3589 if (auSerialIoPortBase[2])
3590 {
3591 InsertConfigInteger(pCfg, "Serial2IoPortBase", auSerialIoPortBase[2]);
3592 InsertConfigInteger(pCfg, "Serial2Irq", auSerialIrq[2]);
3593 }
3594
3595 if (auSerialIoPortBase[3])
3596 {
3597 InsertConfigInteger(pCfg, "Serial3IoPortBase", auSerialIoPortBase[3]);
3598 InsertConfigInteger(pCfg, "Serial3Irq", auSerialIrq[3]);
3599 }
3600
3601 InsertConfigInteger(pCfg, "Parallel0IoPortBase", auParallelIoPortBase[0]);
3602 InsertConfigInteger(pCfg, "Parallel0Irq", auParallelIrq[0]);
3603
3604 InsertConfigInteger(pCfg, "Parallel1IoPortBase", auParallelIoPortBase[1]);
3605 InsertConfigInteger(pCfg, "Parallel1Irq", auParallelIrq[1]);
3606
3607#if defined(VBOX_WITH_TPM)
3608 switch (enmTpmType)
3609 {
3610 case TpmType_v1_2:
3611 InsertConfigString(pCfg, "TpmMode", "tis1.2");
3612 break;
3613 case TpmType_v2_0:
3614 InsertConfigString(pCfg, "TpmMode", "fifo2.0");
3615 break;
3616 /** @todo Host and swtpm. */
3617 default:
3618 break;
3619 }
3620#endif
3621
3622 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3623 InsertConfigString(pLunL0, "Driver", "ACPIHost");
3624 InsertConfigNode(pLunL0, "Config", &pCfg);
3625
3626 /* Attach the dummy CPU drivers */
3627 for (ULONG iCpuCurr = 1; iCpuCurr < cCpus; iCpuCurr++)
3628 {
3629 BOOL fCpuAttached = true;
3630
3631 if (fCpuHotPlug)
3632 {
3633 hrc = pMachine->GetCPUStatus(iCpuCurr, &fCpuAttached); H();
3634 }
3635
3636 if (fCpuAttached)
3637 {
3638 InsertConfigNode(pInst, Utf8StrFmt("LUN#%u", iCpuCurr).c_str(), &pLunL0);
3639 InsertConfigString(pLunL0, "Driver", "ACPICpu");
3640 InsertConfigNode(pLunL0, "Config", &pCfg);
3641 }
3642 }
3643 }
3644
3645 /*
3646 * Configure DBGF (Debug(ger) Facility) and DBGC (Debugger Console).
3647 */
3648 {
3649 PCFGMNODE pDbgf;
3650 InsertConfigNode(pRoot, "DBGF", &pDbgf);
3651
3652 /* Paths to search for debug info and such things. */
3653 hrc = pMachine->COMGETTER(SettingsFilePath)(bstr.asOutParam()); H();
3654 Utf8Str strSettingsPath(bstr);
3655 bstr.setNull();
3656 strSettingsPath.stripFilename();
3657 strSettingsPath.append("/");
3658
3659 char szHomeDir[RTPATH_MAX + 1];
3660 int rc2 = RTPathUserHome(szHomeDir, sizeof(szHomeDir) - 1);
3661 if (RT_FAILURE(rc2))
3662 szHomeDir[0] = '\0';
3663 RTPathEnsureTrailingSeparator(szHomeDir, sizeof(szHomeDir));
3664
3665
3666 Utf8Str strPath;
3667 strPath.append(strSettingsPath).append("debug/;");
3668 strPath.append(strSettingsPath).append(";");
3669 strPath.append("cache*").append(strSettingsPath).append("dbgcache/;"); /* handy for symlinking to actual cache */
3670 strPath.append(szHomeDir);
3671
3672 InsertConfigString(pDbgf, "Path", strPath.c_str());
3673
3674 /* Tracing configuration. */
3675 BOOL fTracingEnabled;
3676 hrc = pMachine->COMGETTER(TracingEnabled)(&fTracingEnabled); H();
3677 if (fTracingEnabled)
3678 InsertConfigInteger(pDbgf, "TracingEnabled", 1);
3679
3680 hrc = pMachine->COMGETTER(TracingConfig)(bstr.asOutParam()); H();
3681 if (fTracingEnabled)
3682 InsertConfigString(pDbgf, "TracingConfig", bstr);
3683
3684 BOOL fAllowTracingToAccessVM;
3685 hrc = pMachine->COMGETTER(AllowTracingToAccessVM)(&fAllowTracingToAccessVM); H();
3686 if (fAllowTracingToAccessVM)
3687 InsertConfigInteger(pPDM, "AllowTracingToAccessVM", 1);
3688
3689 /* Debugger console config. */
3690 PCFGMNODE pDbgc;
3691 InsertConfigNode(pRoot, "DBGC", &pDbgc);
3692
3693 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
3694 Utf8Str strVBoxHome = bstr;
3695 bstr.setNull();
3696 if (strVBoxHome.isNotEmpty())
3697 strVBoxHome.append("/");
3698 else
3699 {
3700 strVBoxHome = szHomeDir;
3701 strVBoxHome.append("/.vbox");
3702 }
3703
3704 Utf8Str strFile(strVBoxHome);
3705 strFile.append("dbgc-history");
3706 InsertConfigString(pDbgc, "HistoryFile", strFile);
3707
3708 strFile = strSettingsPath;
3709 strFile.append("dbgc-init");
3710 InsertConfigString(pDbgc, "LocalInitScript", strFile);
3711
3712 strFile = strVBoxHome;
3713 strFile.append("dbgc-init");
3714 InsertConfigString(pDbgc, "GlobalInitScript", strFile);
3715 }
3716 }
3717 catch (ConfigError &x)
3718 {
3719 // InsertConfig threw something:
3720 VMR3SetError(pUVM, x.m_vrc, RT_SRC_POS, "Caught ConfigError: %Rrc - %s", x.m_vrc, x.what());
3721 return x.m_vrc;
3722 }
3723 catch (HRESULT hrcXcpt)
3724 {
3725 AssertLogRelMsgFailedReturn(("hrc=%Rhrc\n", hrcXcpt), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
3726 }
3727
3728#ifdef VBOX_WITH_EXTPACK
3729 /*
3730 * Call the extension pack hooks if everything went well thus far.
3731 */
3732 if (RT_SUCCESS(rc))
3733 {
3734 pAlock->release();
3735 rc = mptrExtPackManager->i_callAllVmConfigureVmmHooks(this, pVM);
3736 pAlock->acquire();
3737 }
3738#endif
3739
3740 /*
3741 * Apply the CFGM overlay.
3742 */
3743 if (RT_SUCCESS(rc))
3744 rc = i_configCfgmOverlay(pRoot, virtualBox, pMachine);
3745
3746 /*
3747 * Dump all extradata API settings tweaks, both global and per VM.
3748 */
3749 if (RT_SUCCESS(rc))
3750 rc = i_configDumpAPISettingsTweaks(virtualBox, pMachine);
3751
3752#undef H
3753
3754 pAlock->release(); /* Avoid triggering the lock order inversion check. */
3755
3756 /*
3757 * Register VM state change handler.
3758 */
3759 int rc2 = VMR3AtStateRegister(pUVM, Console::i_vmstateChangeCallback, this);
3760 AssertRC(rc2);
3761 if (RT_SUCCESS(rc))
3762 rc = rc2;
3763
3764 /*
3765 * Register VM runtime error handler.
3766 */
3767 rc2 = VMR3AtRuntimeErrorRegister(pUVM, Console::i_atVMRuntimeErrorCallback, this);
3768 AssertRC(rc2);
3769 if (RT_SUCCESS(rc))
3770 rc = rc2;
3771
3772 pAlock->acquire();
3773
3774 LogFlowFunc(("vrc = %Rrc\n", rc));
3775 LogFlowFuncLeave();
3776
3777 return rc;
3778}
3779
3780/**
3781 * Configures an audio driver via CFGM by getting (optional) values from extra data.
3782 *
3783 * @param pVirtualBox Pointer to IVirtualBox instance.
3784 * @param pMachine Pointer to IMachine instance.
3785 * @param pLUN Pointer to CFGM node of LUN (the driver) to configure.
3786 * @param pszDrvName Name of the driver to configure.
3787 * @param fAudioEnabledIn IAudioAdapter::enabledIn value.
3788 * @param fAudioEnabledOut IAudioAdapter::enabledOut value.
3789 *
3790 * @throws ConfigError or HRESULT on if there is trouble.
3791 */
3792void Console::i_configAudioDriver(IVirtualBox *pVirtualBox, IMachine *pMachine, PCFGMNODE pLUN, const char *pszDrvName,
3793 bool fAudioEnabledIn, bool fAudioEnabledOut)
3794{
3795#define H() AssertLogRelMsgStmt(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), \
3796 throw ConfigError(__FUNCTION__, VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR, "line: " RT_XSTR(__LINE__)))
3797
3798 InsertConfigString(pLUN, "Driver", "AUDIO");
3799
3800 PCFGMNODE pCfg;
3801 InsertConfigNode(pLUN, "Config", &pCfg);
3802 InsertConfigString(pCfg, "DriverName", pszDrvName);
3803 InsertConfigInteger(pCfg, "InputEnabled", fAudioEnabledIn);
3804 InsertConfigInteger(pCfg, "OutputEnabled", fAudioEnabledOut);
3805
3806 Utf8Str strTmp;
3807 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/Audio/Debug/Enabled", &strTmp);
3808 const uint64_t fDebugEnabled = strTmp.equalsIgnoreCase("true") || strTmp.equalsIgnoreCase("1");
3809 if (fDebugEnabled)
3810 {
3811 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
3812
3813 Utf8Str strDebugPathOut;
3814 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/Audio/Debug/PathOut", &strDebugPathOut);
3815 InsertConfigString(pCfg, "DebugPathOut", strDebugPathOut.c_str());
3816 }
3817
3818 /*
3819 * PCM input parameters (playback + recording).
3820 * We have host driver specific ones as: VBoxInternal2/Audio/<DrvName>/<Value>
3821 * And global ones for all host drivers: VBoxInternal2/Audio/<Value>
3822 */
3823 for (unsigned iDir = 0; iDir < 2; iDir++)
3824 {
3825 static const struct
3826 {
3827 const char *pszExtraName;
3828 const char *pszCfgmName;
3829 } s_aToCopy[] =
3830 { /* PCM parameters: */
3831 { "PCMSampleBit", "PCMSampleBit" },
3832 { "PCMSampleHz", "PCMSampleHz" },
3833 { "PCMSampleSigned", "PCMSampleSigned" },
3834 { "PCMSampleSwapEndian", "PCMSampleSwapEndian" },
3835 { "PCMSampleChannels", "PCMSampleChannels" },
3836 /* Buffering stuff: */
3837 { "PeriodSizeMs", "PeriodSizeMs" },
3838 { "BufferSizeMs", "BufferSizeMs" },
3839 { "PreBufferSizeMs", "PreBufferSizeMs" },
3840 };
3841
3842 PCFGMNODE pDirNode = NULL;
3843 const char *pszDir = iDir == 0 ? "In" : "Out";
3844 for (size_t i = 0; i < RT_ELEMENTS(s_aToCopy); i++)
3845 {
3846 char szExtra[128];
3847 RTStrPrintf(szExtra, sizeof(szExtra), "VBoxInternal2/Audio/%s/%s%s", pszDrvName, s_aToCopy[i].pszExtraName, pszDir);
3848 GetExtraDataBoth(pVirtualBox, pMachine, szExtra, &strTmp); /* throws hrc */
3849 if (strTmp.isEmpty())
3850 {
3851 RTStrPrintf(szExtra, sizeof(szExtra), "VBoxInternal2/Audio/%s%s", s_aToCopy[i].pszExtraName, pszDir);
3852 GetExtraDataBoth(pVirtualBox, pMachine, szExtra, &strTmp);
3853 if (strTmp.isEmpty())
3854 continue;
3855 }
3856
3857 uint32_t uValue;
3858 int vrc = RTStrToUInt32Full(strTmp.c_str(), 0, &uValue);
3859 if (RT_SUCCESS(vrc))
3860 {
3861 if (!pDirNode)
3862 InsertConfigNode(pCfg, pszDir, &pDirNode);
3863 InsertConfigInteger(pDirNode, s_aToCopy[i].pszCfgmName, uValue);
3864 }
3865 else
3866 LogRel(("Ignoring malformed 32-bit unsigned integer config value '%s' = '%s': %Rrc\n", szExtra, strTmp.c_str(), vrc));
3867 }
3868 }
3869
3870 PCFGMNODE pLunL1;
3871 InsertConfigNode(pLUN, "AttachedDriver", &pLunL1);
3872 InsertConfigString(pLunL1, "Driver", pszDrvName);
3873 InsertConfigNode(pLunL1, "Config", &pCfg);
3874
3875#ifdef RT_OS_WINDOWS
3876 if (strcmp(pszDrvName, "HostAudioWas") == 0)
3877 {
3878 Bstr bstrTmp;
3879 HRESULT hrc = pMachine->COMGETTER(Id)(bstrTmp.asOutParam()); H();
3880 InsertConfigString(pCfg, "VmUuid", bstrTmp);
3881 }
3882#endif
3883
3884#if defined(RT_OS_WINDOWS) || defined(RT_OS_LINUX)
3885 if ( strcmp(pszDrvName, "HostAudioWas") == 0
3886 || strcmp(pszDrvName, "PulseAudio") == 0)
3887 {
3888 Bstr bstrTmp;
3889 HRESULT hrc = pMachine->COMGETTER(Name)(bstrTmp.asOutParam()); H();
3890 InsertConfigString(pCfg, "VmName", bstrTmp);
3891 }
3892#endif
3893
3894 LogFlowFunc(("szDrivName=%s\n", pszDrvName));
3895
3896#undef H
3897}
3898
3899/**
3900 * Applies the CFGM overlay as specified by VBoxInternal/XXX extra data
3901 * values.
3902 *
3903 * @returns VBox status code.
3904 * @param pRoot The root of the configuration tree.
3905 * @param pVirtualBox Pointer to the IVirtualBox interface.
3906 * @param pMachine Pointer to the IMachine interface.
3907 */
3908/* static */
3909int Console::i_configCfgmOverlay(PCFGMNODE pRoot, IVirtualBox *pVirtualBox, IMachine *pMachine)
3910{
3911 /*
3912 * CFGM overlay handling.
3913 *
3914 * Here we check the extra data entries for CFGM values
3915 * and create the nodes and insert the values on the fly. Existing
3916 * values will be removed and reinserted. CFGM is typed, so by default
3917 * we will guess whether it's a string or an integer (byte arrays are
3918 * not currently supported). It's possible to override this autodetection
3919 * by adding "string:", "integer:" or "bytes:" (future).
3920 *
3921 * We first perform a run on global extra data, then on the machine
3922 * extra data to support global settings with local overrides.
3923 */
3924 int rc = VINF_SUCCESS;
3925 bool fFirst = true;
3926 try
3927 {
3928 /** @todo add support for removing nodes and byte blobs. */
3929 /*
3930 * Get the next key
3931 */
3932 SafeArray<BSTR> aGlobalExtraDataKeys;
3933 SafeArray<BSTR> aMachineExtraDataKeys;
3934 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
3935 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
3936
3937 // remember the no. of global values so we can call the correct method below
3938 size_t cGlobalValues = aGlobalExtraDataKeys.size();
3939
3940 hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
3941 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
3942
3943 // build a combined list from global keys...
3944 std::list<Utf8Str> llExtraDataKeys;
3945
3946 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); ++i)
3947 llExtraDataKeys.push_back(Utf8Str(aGlobalExtraDataKeys[i]));
3948 // ... and machine keys
3949 for (size_t i = 0; i < aMachineExtraDataKeys.size(); ++i)
3950 llExtraDataKeys.push_back(Utf8Str(aMachineExtraDataKeys[i]));
3951
3952 size_t i2 = 0;
3953 for (std::list<Utf8Str>::const_iterator it = llExtraDataKeys.begin();
3954 it != llExtraDataKeys.end();
3955 ++it, ++i2)
3956 {
3957 const Utf8Str &strKey = *it;
3958
3959 /*
3960 * We only care about keys starting with "VBoxInternal/" (skip "G:" or "M:")
3961 */
3962 if (!strKey.startsWith("VBoxInternal/"))
3963 continue;
3964
3965 const char *pszExtraDataKey = strKey.c_str() + sizeof("VBoxInternal/") - 1;
3966
3967 // get the value
3968 Bstr bstrExtraDataValue;
3969 if (i2 < cGlobalValues)
3970 // this is still one of the global values:
3971 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
3972 bstrExtraDataValue.asOutParam());
3973 else
3974 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
3975 bstrExtraDataValue.asOutParam());
3976 if (FAILED(hrc))
3977 LogRel(("Warning: Cannot get extra data key %s, rc = %Rhrc\n", strKey.c_str(), hrc));
3978
3979 if (fFirst)
3980 {
3981 fFirst = false;
3982 LogRel(("Extradata overrides:\n"));
3983 }
3984 LogRel((" %s=\"%ls\"%s\n", strKey.c_str(), bstrExtraDataValue.raw(), i2 < cGlobalValues ? " (global)" : ""));
3985
3986 /*
3987 * The key will be in the format "Node1/Node2/Value" or simply "Value".
3988 * Split the two and get the node, delete the value and create the node
3989 * if necessary.
3990 */
3991 PCFGMNODE pNode;
3992 const char *pszCFGMValueName = strrchr(pszExtraDataKey, '/');
3993 if (pszCFGMValueName)
3994 {
3995 /* terminate the node and advance to the value (Utf8Str might not
3996 offically like this but wtf) */
3997 *(char *)pszCFGMValueName = '\0';
3998 ++pszCFGMValueName;
3999
4000 /* does the node already exist? */
4001 pNode = CFGMR3GetChild(pRoot, pszExtraDataKey);
4002 if (pNode)
4003 CFGMR3RemoveValue(pNode, pszCFGMValueName);
4004 else
4005 {
4006 /* create the node */
4007 rc = CFGMR3InsertNode(pRoot, pszExtraDataKey, &pNode);
4008 if (RT_FAILURE(rc))
4009 {
4010 AssertLogRelMsgRC(rc, ("failed to insert node '%s'\n", pszExtraDataKey));
4011 continue;
4012 }
4013 Assert(pNode);
4014 }
4015 }
4016 else
4017 {
4018 /* root value (no node path). */
4019 pNode = pRoot;
4020 pszCFGMValueName = pszExtraDataKey;
4021 pszExtraDataKey--;
4022 CFGMR3RemoveValue(pNode, pszCFGMValueName);
4023 }
4024
4025 /*
4026 * Now let's have a look at the value.
4027 * Empty strings means that we should remove the value, which we've
4028 * already done above.
4029 */
4030 Utf8Str strCFGMValueUtf8(bstrExtraDataValue);
4031 if (!strCFGMValueUtf8.isEmpty())
4032 {
4033 uint64_t u64Value;
4034
4035 /* check for type prefix first. */
4036 if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("string:")))
4037 InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8.c_str() + sizeof("string:") - 1);
4038 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("integer:")))
4039 {
4040 rc = RTStrToUInt64Full(strCFGMValueUtf8.c_str() + sizeof("integer:") - 1, 0, &u64Value);
4041 if (RT_SUCCESS(rc))
4042 rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
4043 }
4044 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("bytes:")))
4045 {
4046 char const *pszBase64 = strCFGMValueUtf8.c_str() + sizeof("bytes:") - 1;
4047 ssize_t cbValue = RTBase64DecodedSize(pszBase64, NULL);
4048 if (cbValue > 0)
4049 {
4050 void *pvBytes = RTMemTmpAlloc(cbValue);
4051 if (pvBytes)
4052 {
4053 rc = RTBase64Decode(pszBase64, pvBytes, cbValue, NULL, NULL);
4054 if (RT_SUCCESS(rc))
4055 rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, pvBytes, cbValue);
4056 RTMemTmpFree(pvBytes);
4057 }
4058 else
4059 rc = VERR_NO_TMP_MEMORY;
4060 }
4061 else if (cbValue == 0)
4062 rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, NULL, 0);
4063 else
4064 rc = VERR_INVALID_BASE64_ENCODING;
4065 }
4066 /* auto detect type. */
4067 else if (RT_SUCCESS(RTStrToUInt64Full(strCFGMValueUtf8.c_str(), 0, &u64Value)))
4068 rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
4069 else
4070 InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8);
4071 AssertLogRelMsgRCBreak(rc, ("failed to insert CFGM value '%s' to key '%s'\n",
4072 strCFGMValueUtf8.c_str(), pszExtraDataKey));
4073 }
4074 }
4075 }
4076 catch (ConfigError &x)
4077 {
4078 // InsertConfig threw something:
4079 return x.m_vrc;
4080 }
4081 return rc;
4082}
4083
4084/**
4085 * Dumps the API settings tweaks as specified by VBoxInternal2/XXX extra data
4086 * values.
4087 *
4088 * @returns VBox status code.
4089 * @param pVirtualBox Pointer to the IVirtualBox interface.
4090 * @param pMachine Pointer to the IMachine interface.
4091 */
4092/* static */
4093int Console::i_configDumpAPISettingsTweaks(IVirtualBox *pVirtualBox, IMachine *pMachine)
4094{
4095 {
4096 SafeArray<BSTR> aGlobalExtraDataKeys;
4097 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
4098 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
4099 bool hasKey = false;
4100 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); i++)
4101 {
4102 Utf8Str strKey(aGlobalExtraDataKeys[i]);
4103 if (!strKey.startsWith("VBoxInternal2/"))
4104 continue;
4105
4106 Bstr bstrValue;
4107 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
4108 bstrValue.asOutParam());
4109 if (FAILED(hrc))
4110 continue;
4111 if (!hasKey)
4112 LogRel(("Global extradata API settings:\n"));
4113 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
4114 hasKey = true;
4115 }
4116 }
4117
4118 {
4119 SafeArray<BSTR> aMachineExtraDataKeys;
4120 HRESULT hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
4121 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
4122 bool hasKey = false;
4123 for (size_t i = 0; i < aMachineExtraDataKeys.size(); i++)
4124 {
4125 Utf8Str strKey(aMachineExtraDataKeys[i]);
4126 if (!strKey.startsWith("VBoxInternal2/"))
4127 continue;
4128
4129 Bstr bstrValue;
4130 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
4131 bstrValue.asOutParam());
4132 if (FAILED(hrc))
4133 continue;
4134 if (!hasKey)
4135 LogRel(("Per-VM extradata API settings:\n"));
4136 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
4137 hasKey = true;
4138 }
4139 }
4140
4141 return VINF_SUCCESS;
4142}
4143
4144int Console::i_configGraphicsController(PCFGMNODE pDevices,
4145 const GraphicsControllerType_T enmGraphicsController,
4146 BusAssignmentManager *pBusMgr,
4147 const ComPtr<IMachine> &ptrMachine,
4148 const ComPtr<IGraphicsAdapter> &ptrGraphicsAdapter,
4149 const ComPtr<IBIOSSettings> &ptrBiosSettings,
4150 bool fHMEnabled)
4151{
4152 // InsertConfig* throws
4153 try
4154 {
4155 PCFGMNODE pDev, pInst, pCfg, pLunL0;
4156 HRESULT hrc;
4157 Bstr bstr;
4158 const char *pcszDevice = "vga";
4159
4160#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4161 InsertConfigNode(pDevices, pcszDevice, &pDev);
4162 InsertConfigNode(pDev, "0", &pInst);
4163 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
4164
4165 hrc = pBusMgr->assignPCIDevice(pcszDevice, pInst); H();
4166 InsertConfigNode(pInst, "Config", &pCfg);
4167 ULONG cVRamMBs;
4168 hrc = ptrGraphicsAdapter->COMGETTER(VRAMSize)(&cVRamMBs); H();
4169 InsertConfigInteger(pCfg, "VRamSize", cVRamMBs * _1M);
4170 ULONG cMonitorCount;
4171 hrc = ptrGraphicsAdapter->COMGETTER(MonitorCount)(&cMonitorCount); H();
4172 InsertConfigInteger(pCfg, "MonitorCount", cMonitorCount);
4173#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
4174 InsertConfigInteger(pCfg, "R0Enabled", fHMEnabled);
4175#else
4176 NOREF(fHMEnabled);
4177#endif
4178 BOOL f3DEnabled;
4179 hrc = ptrGraphicsAdapter->COMGETTER(Accelerate3DEnabled)(&f3DEnabled); H();
4180 InsertConfigInteger(pCfg, "3DEnabled", f3DEnabled);
4181
4182 i_attachStatusDriver(pInst, DeviceType_Graphics3D, 0, 0, NULL, NULL, NULL, 0);
4183
4184#ifdef VBOX_WITH_VMSVGA
4185 if ( enmGraphicsController == GraphicsControllerType_VMSVGA
4186 || enmGraphicsController == GraphicsControllerType_VBoxSVGA)
4187 {
4188 InsertConfigInteger(pCfg, "VMSVGAEnabled", true);
4189 if (enmGraphicsController == GraphicsControllerType_VMSVGA)
4190 {
4191 InsertConfigInteger(pCfg, "VMSVGAPciBarLayout", true);
4192 InsertConfigInteger(pCfg, "VMSVGAPciId", true);
4193 }
4194# ifdef VBOX_WITH_VMSVGA3D
4195 InsertConfigInteger(pCfg, "VMSVGA3dEnabled", f3DEnabled);
4196# else
4197 LogRel(("VMSVGA3d not available in this build!\n"));
4198# endif /* VBOX_WITH_VMSVGA3D */
4199 }
4200#else
4201 RT_NOREF(enmGraphicsController);
4202#endif /* VBOX_WITH_VMSVGA */
4203
4204 /* Custom VESA mode list */
4205 unsigned cModes = 0;
4206 for (unsigned iMode = 1; iMode <= 16; ++iMode)
4207 {
4208 char szExtraDataKey[sizeof("CustomVideoModeXX")];
4209 RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%u", iMode);
4210 hrc = ptrMachine->GetExtraData(Bstr(szExtraDataKey).raw(), bstr.asOutParam()); H();
4211 if (bstr.isEmpty())
4212 break;
4213 InsertConfigString(pCfg, szExtraDataKey, bstr);
4214 ++cModes;
4215 }
4216 InsertConfigInteger(pCfg, "CustomVideoModes", cModes);
4217
4218 /* VESA height reduction */
4219 ULONG ulHeightReduction;
4220 IFramebuffer *pFramebuffer = NULL;
4221 hrc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
4222 if (SUCCEEDED(hrc) && pFramebuffer)
4223 {
4224 hrc = pFramebuffer->COMGETTER(HeightReduction)(&ulHeightReduction); H();
4225 pFramebuffer->Release();
4226 pFramebuffer = NULL;
4227 }
4228 else
4229 {
4230 /* If framebuffer is not available, there is no height reduction. */
4231 ulHeightReduction = 0;
4232 }
4233 InsertConfigInteger(pCfg, "HeightReduction", ulHeightReduction);
4234
4235 /*
4236 * BIOS logo
4237 */
4238 BOOL fFadeIn;
4239 hrc = ptrBiosSettings->COMGETTER(LogoFadeIn)(&fFadeIn); H();
4240 InsertConfigInteger(pCfg, "FadeIn", fFadeIn ? 1 : 0);
4241 BOOL fFadeOut;
4242 hrc = ptrBiosSettings->COMGETTER(LogoFadeOut)(&fFadeOut); H();
4243 InsertConfigInteger(pCfg, "FadeOut", fFadeOut ? 1: 0);
4244 ULONG logoDisplayTime;
4245 hrc = ptrBiosSettings->COMGETTER(LogoDisplayTime)(&logoDisplayTime); H();
4246 InsertConfigInteger(pCfg, "LogoTime", logoDisplayTime);
4247 Bstr logoImagePath;
4248 hrc = ptrBiosSettings->COMGETTER(LogoImagePath)(logoImagePath.asOutParam()); H();
4249 InsertConfigString(pCfg, "LogoFile", Utf8Str(!logoImagePath.isEmpty() ? logoImagePath : "") );
4250
4251 /*
4252 * Boot menu
4253 */
4254 BIOSBootMenuMode_T eBootMenuMode;
4255 int iShowBootMenu;
4256 hrc = ptrBiosSettings->COMGETTER(BootMenuMode)(&eBootMenuMode); H();
4257 switch (eBootMenuMode)
4258 {
4259 case BIOSBootMenuMode_Disabled: iShowBootMenu = 0; break;
4260 case BIOSBootMenuMode_MenuOnly: iShowBootMenu = 1; break;
4261 default: iShowBootMenu = 2; break;
4262 }
4263 InsertConfigInteger(pCfg, "ShowBootMenu", iShowBootMenu);
4264
4265 /* Attach the display. */
4266 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4267 InsertConfigString(pLunL0, "Driver", "MainDisplay");
4268 InsertConfigNode(pLunL0, "Config", &pCfg);
4269 }
4270 catch (ConfigError &x)
4271 {
4272 // InsertConfig threw something:
4273 return x.m_vrc;
4274 }
4275
4276#undef H
4277
4278 return VINF_SUCCESS;
4279}
4280
4281
4282/**
4283 * Ellipsis to va_list wrapper for calling setVMRuntimeErrorCallback.
4284 */
4285void Console::i_atVMRuntimeErrorCallbackF(uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)
4286{
4287 va_list va;
4288 va_start(va, pszFormat);
4289 i_atVMRuntimeErrorCallback(NULL, this, fFlags, pszErrorId, pszFormat, va);
4290 va_end(va);
4291}
4292
4293/* XXX introduce RT format specifier */
4294static uint64_t formatDiskSize(uint64_t u64Size, const char **pszUnit)
4295{
4296 if (u64Size > INT64_C(5000)*_1G)
4297 {
4298 *pszUnit = "TB";
4299 return u64Size / _1T;
4300 }
4301 else if (u64Size > INT64_C(5000)*_1M)
4302 {
4303 *pszUnit = "GB";
4304 return u64Size / _1G;
4305 }
4306 else
4307 {
4308 *pszUnit = "MB";
4309 return u64Size / _1M;
4310 }
4311}
4312
4313/**
4314 * Checks the location of the given medium for known bugs affecting the usage
4315 * of the host I/O cache setting.
4316 *
4317 * @returns VBox status code.
4318 * @param pMedium The medium to check.
4319 * @param pfUseHostIOCache Where to store the suggested host I/O cache setting.
4320 */
4321int Console::i_checkMediumLocation(IMedium *pMedium, bool *pfUseHostIOCache)
4322{
4323#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4324 /*
4325 * Some sanity checks.
4326 */
4327 RT_NOREF(pfUseHostIOCache);
4328 ComPtr<IMediumFormat> pMediumFormat;
4329 HRESULT hrc = pMedium->COMGETTER(MediumFormat)(pMediumFormat.asOutParam()); H();
4330 ULONG uCaps = 0;
4331 com::SafeArray <MediumFormatCapabilities_T> mediumFormatCap;
4332 hrc = pMediumFormat->COMGETTER(Capabilities)(ComSafeArrayAsOutParam(mediumFormatCap)); H();
4333
4334 for (ULONG j = 0; j < mediumFormatCap.size(); j++)
4335 uCaps |= mediumFormatCap[j];
4336
4337 if (uCaps & MediumFormatCapabilities_File)
4338 {
4339 Bstr strFile;
4340 hrc = pMedium->COMGETTER(Location)(strFile.asOutParam()); H();
4341 Utf8Str utfFile = Utf8Str(strFile);
4342 Bstr strSnap;
4343 ComPtr<IMachine> pMachine = i_machine();
4344 hrc = pMachine->COMGETTER(SnapshotFolder)(strSnap.asOutParam()); H();
4345 Utf8Str utfSnap = Utf8Str(strSnap);
4346 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
4347 RTFSTYPE enmFsTypeSnap = RTFSTYPE_UNKNOWN;
4348 int rc2 = RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
4349 AssertMsgRCReturn(rc2, ("Querying the file type of '%s' failed!\n", utfFile.c_str()), rc2);
4350 /* Ignore the error code. On error, the file system type is still 'unknown' so
4351 * none of the following paths are taken. This can happen for new VMs which
4352 * still don't have a snapshot folder. */
4353 (void)RTFsQueryType(utfSnap.c_str(), &enmFsTypeSnap);
4354 if (!mfSnapshotFolderDiskTypeShown)
4355 {
4356 LogRel(("File system of '%s' (snapshots) is %s\n",
4357 utfSnap.c_str(), RTFsTypeName(enmFsTypeSnap)));
4358 mfSnapshotFolderDiskTypeShown = true;
4359 }
4360 LogRel(("File system of '%s' is %s\n", utfFile.c_str(), RTFsTypeName(enmFsTypeFile)));
4361 LONG64 i64Size;
4362 hrc = pMedium->COMGETTER(LogicalSize)(&i64Size); H();
4363#ifdef RT_OS_WINDOWS
4364 if ( enmFsTypeFile == RTFSTYPE_FAT
4365 && i64Size >= _4G)
4366 {
4367 const char *pszUnit;
4368 uint64_t u64Print = formatDiskSize((uint64_t)i64Size, &pszUnit);
4369 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
4370 N_("The medium '%ls' has a logical size of %RU64%s "
4371 "but the file system the medium is located on seems "
4372 "to be FAT(32) which cannot handle files bigger than 4GB.\n"
4373 "We strongly recommend to put all your virtual disk images and "
4374 "the snapshot folder onto an NTFS partition"),
4375 strFile.raw(), u64Print, pszUnit);
4376 }
4377#else /* !RT_OS_WINDOWS */
4378 if ( enmFsTypeFile == RTFSTYPE_FAT
4379 || enmFsTypeFile == RTFSTYPE_EXT
4380 || enmFsTypeFile == RTFSTYPE_EXT2
4381 || enmFsTypeFile == RTFSTYPE_EXT3
4382 || enmFsTypeFile == RTFSTYPE_EXT4)
4383 {
4384 RTFILE file;
4385 int rc = RTFileOpen(&file, utfFile.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
4386 if (RT_SUCCESS(rc))
4387 {
4388 RTFOFF maxSize;
4389 /* Careful: This function will work only on selected local file systems! */
4390 rc = RTFileQueryMaxSizeEx(file, &maxSize);
4391 RTFileClose(file);
4392 if ( RT_SUCCESS(rc)
4393 && maxSize > 0
4394 && i64Size > (LONG64)maxSize)
4395 {
4396 const char *pszUnitSiz;
4397 const char *pszUnitMax;
4398 uint64_t u64PrintSiz = formatDiskSize((LONG64)i64Size, &pszUnitSiz);
4399 uint64_t u64PrintMax = formatDiskSize(maxSize, &pszUnitMax);
4400 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected", /* <= not exact but ... */
4401 N_("The medium '%ls' has a logical size of %RU64%s "
4402 "but the file system the medium is located on can "
4403 "only handle files up to %RU64%s in theory.\n"
4404 "We strongly recommend to put all your virtual disk "
4405 "images and the snapshot folder onto a proper "
4406 "file system (e.g. ext3) with a sufficient size"),
4407 strFile.raw(), u64PrintSiz, pszUnitSiz, u64PrintMax, pszUnitMax);
4408 }
4409 }
4410 }
4411#endif /* !RT_OS_WINDOWS */
4412
4413 /*
4414 * Snapshot folder:
4415 * Here we test only for a FAT partition as we had to create a dummy file otherwise
4416 */
4417 if ( enmFsTypeSnap == RTFSTYPE_FAT
4418 && i64Size >= _4G
4419 && !mfSnapshotFolderSizeWarningShown)
4420 {
4421 const char *pszUnit;
4422 uint64_t u64Print = formatDiskSize(i64Size, &pszUnit);
4423 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
4424#ifdef RT_OS_WINDOWS
4425 N_("The snapshot folder of this VM '%ls' seems to be located on "
4426 "a FAT(32) file system. The logical size of the medium '%ls' "
4427 "(%RU64%s) is bigger than the maximum file size this file "
4428 "system can handle (4GB).\n"
4429 "We strongly recommend to put all your virtual disk images and "
4430 "the snapshot folder onto an NTFS partition"),
4431#else
4432 N_("The snapshot folder of this VM '%ls' seems to be located on "
4433 "a FAT(32) file system. The logical size of the medium '%ls' "
4434 "(%RU64%s) is bigger than the maximum file size this file "
4435 "system can handle (4GB).\n"
4436 "We strongly recommend to put all your virtual disk images and "
4437 "the snapshot folder onto a proper file system (e.g. ext3)"),
4438#endif
4439 strSnap.raw(), strFile.raw(), u64Print, pszUnit);
4440 /* Show this particular warning only once */
4441 mfSnapshotFolderSizeWarningShown = true;
4442 }
4443
4444#ifdef RT_OS_LINUX
4445 /*
4446 * Ext4 bug: Check if the host I/O cache is disabled and the disk image is located
4447 * on an ext4 partition.
4448 * This bug apparently applies to the XFS file system as well.
4449 * Linux 2.6.36 is known to be fixed (tested with 2.6.36-rc4).
4450 */
4451
4452 char szOsRelease[128];
4453 int rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOsRelease, sizeof(szOsRelease));
4454 bool fKernelHasODirectBug = RT_FAILURE(rc)
4455 || (RTStrVersionCompare(szOsRelease, "2.6.36-rc4") < 0);
4456
4457 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
4458 && !*pfUseHostIOCache
4459 && fKernelHasODirectBug)
4460 {
4461 if ( enmFsTypeFile == RTFSTYPE_EXT4
4462 || enmFsTypeFile == RTFSTYPE_XFS)
4463 {
4464 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
4465 N_("The host I/O cache for at least one controller is disabled "
4466 "and the medium '%ls' for this VM "
4467 "is located on an %s partition. There is a known Linux "
4468 "kernel bug which can lead to the corruption of the virtual "
4469 "disk image under these conditions.\n"
4470 "Either enable the host I/O cache permanently in the VM "
4471 "settings or put the disk image and the snapshot folder "
4472 "onto a different file system.\n"
4473 "The host I/O cache will now be enabled for this medium"),
4474 strFile.raw(), enmFsTypeFile == RTFSTYPE_EXT4 ? "ext4" : "xfs");
4475 *pfUseHostIOCache = true;
4476 }
4477 else if ( ( enmFsTypeSnap == RTFSTYPE_EXT4
4478 || enmFsTypeSnap == RTFSTYPE_XFS)
4479 && !mfSnapshotFolderExt4WarningShown)
4480 {
4481 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
4482 N_("The host I/O cache for at least one controller is disabled "
4483 "and the snapshot folder for this VM "
4484 "is located on an %s partition. There is a known Linux "
4485 "kernel bug which can lead to the corruption of the virtual "
4486 "disk image under these conditions.\n"
4487 "Either enable the host I/O cache permanently in the VM "
4488 "settings or put the disk image and the snapshot folder "
4489 "onto a different file system.\n"
4490 "The host I/O cache will now be enabled for this medium"),
4491 enmFsTypeSnap == RTFSTYPE_EXT4 ? "ext4" : "xfs");
4492 *pfUseHostIOCache = true;
4493 mfSnapshotFolderExt4WarningShown = true;
4494 }
4495 }
4496
4497 /*
4498 * 2.6.18 bug: Check if the host I/O cache is disabled and the host is running
4499 * Linux 2.6.18. See @bugref{8690}. Apparently the same problem as
4500 * documented in https://lkml.org/lkml/2007/2/1/14. We saw such
4501 * kernel oopses on Linux 2.6.18-416.el5. We don't know when this
4502 * was fixed but we _know_ that 2.6.18 EL5 kernels are affected.
4503 */
4504 bool fKernelAsyncUnreliable = RT_FAILURE(rc)
4505 || (RTStrVersionCompare(szOsRelease, "2.6.19") < 0);
4506 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
4507 && !*pfUseHostIOCache
4508 && fKernelAsyncUnreliable)
4509 {
4510 i_atVMRuntimeErrorCallbackF(0, "Linux2618TooOld",
4511 N_("The host I/O cache for at least one controller is disabled. "
4512 "There is a known Linux kernel bug which can lead to kernel "
4513 "oopses under heavy load. To our knowledge this bug affects "
4514 "all 2.6.18 kernels.\n"
4515 "Either enable the host I/O cache permanently in the VM "
4516 "settings or switch to a newer host kernel.\n"
4517 "The host I/O cache will now be enabled for this medium"));
4518 *pfUseHostIOCache = true;
4519 }
4520#endif
4521 }
4522#undef H
4523
4524 return VINF_SUCCESS;
4525}
4526
4527/**
4528 * Unmounts the specified medium from the specified device.
4529 *
4530 * @returns VBox status code.
4531 * @param pUVM The usermode VM handle.
4532 * @param enmBus The storage bus.
4533 * @param enmDevType The device type.
4534 * @param pcszDevice The device emulation.
4535 * @param uInstance Instance of the device.
4536 * @param uLUN The LUN on the device.
4537 * @param fForceUnmount Whether to force unmounting.
4538 */
4539int Console::i_unmountMediumFromGuest(PUVM pUVM, StorageBus_T enmBus, DeviceType_T enmDevType,
4540 const char *pcszDevice, unsigned uInstance, unsigned uLUN,
4541 bool fForceUnmount)
4542{
4543 /* Unmount existing media only for floppy and DVD drives. */
4544 int rc = VINF_SUCCESS;
4545 PPDMIBASE pBase;
4546 if (enmBus == StorageBus_USB)
4547 rc = PDMR3UsbQueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
4548 else if ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI || enmBus == StorageBus_VirtioSCSI)
4549 || (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD))
4550 rc = PDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
4551 else /* IDE or Floppy */
4552 rc = PDMR3QueryLun(pUVM, pcszDevice, uInstance, uLUN, &pBase);
4553
4554 if (RT_FAILURE(rc))
4555 {
4556 if (rc == VERR_PDM_LUN_NOT_FOUND || rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4557 rc = VINF_SUCCESS;
4558 AssertRC(rc);
4559 }
4560 else
4561 {
4562 PPDMIMOUNT pIMount = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMOUNT);
4563 AssertReturn(pIMount, VERR_INVALID_POINTER);
4564
4565 /* Unmount the media (but do not eject the medium!) */
4566 rc = pIMount->pfnUnmount(pIMount, fForceUnmount, false /*=fEject*/);
4567 if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
4568 rc = VINF_SUCCESS;
4569 /* for example if the medium is locked */
4570 else if (RT_FAILURE(rc))
4571 return rc;
4572 }
4573
4574 return rc;
4575}
4576
4577/**
4578 * Removes the currently attached medium driver form the specified device
4579 * taking care of the controlelr specific configs wrt. to the attached driver chain.
4580 *
4581 * @returns VBox status code.
4582 * @param pCtlInst The controler instance node in the CFGM tree.
4583 * @param pcszDevice The device name.
4584 * @param uInstance The device instance.
4585 * @param uLUN The device LUN.
4586 * @param enmBus The storage bus.
4587 * @param fAttachDetach Flag whether this is a change while the VM is running
4588 * @param fHotplug Flag whether the guest should be notified about the device change.
4589 * @param fForceUnmount Flag whether to force unmounting the medium even if it is locked.
4590 * @param pUVM The usermode VM handle.
4591 * @param enmDevType The device type.
4592 * @param ppLunL0 Where to store the node to attach the new config to on success.
4593 */
4594int Console::i_removeMediumDriverFromVm(PCFGMNODE pCtlInst,
4595 const char *pcszDevice,
4596 unsigned uInstance,
4597 unsigned uLUN,
4598 StorageBus_T enmBus,
4599 bool fAttachDetach,
4600 bool fHotplug,
4601 bool fForceUnmount,
4602 PUVM pUVM,
4603 DeviceType_T enmDevType,
4604 PCFGMNODE *ppLunL0)
4605{
4606 int rc = VINF_SUCCESS;
4607 bool fAddLun = false;
4608
4609 /* First check if the LUN already exists. */
4610 PCFGMNODE pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
4611 AssertReturn(!RT_VALID_PTR(pLunL0) || fAttachDetach, VERR_INTERNAL_ERROR);
4612
4613 if (pLunL0)
4614 {
4615 /*
4616 * Unmount the currently mounted medium if we don't just hot remove the
4617 * complete device (SATA) and it supports unmounting (DVD).
4618 */
4619 if ( (enmDevType != DeviceType_HardDisk)
4620 && !fHotplug)
4621 {
4622 rc = i_unmountMediumFromGuest(pUVM, enmBus, enmDevType, pcszDevice,
4623 uInstance, uLUN, fForceUnmount);
4624 if (RT_FAILURE(rc))
4625 return rc;
4626 }
4627
4628 /*
4629 * Don't detach the SCSI driver when unmounting the current medium
4630 * (we are not ripping out the device but only eject the medium).
4631 */
4632 char *pszDriverDetach = NULL;
4633 if ( !fHotplug
4634 && ( (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD)
4635 || enmBus == StorageBus_SAS
4636 || enmBus == StorageBus_SCSI
4637 || enmBus == StorageBus_VirtioSCSI
4638 || enmBus == StorageBus_USB))
4639 {
4640 /* Get the current attached driver we have to detach. */
4641 PCFGMNODE pDrvLun = CFGMR3GetChildF(pCtlInst, "LUN#%u/AttachedDriver/", uLUN);
4642 if (pDrvLun)
4643 {
4644 char szDriver[128];
4645 RT_ZERO(szDriver);
4646 rc = CFGMR3QueryString(pDrvLun, "Driver", &szDriver[0], sizeof(szDriver));
4647 if (RT_SUCCESS(rc))
4648 pszDriverDetach = RTStrDup(&szDriver[0]);
4649
4650 pLunL0 = pDrvLun;
4651 }
4652 }
4653
4654 if (enmBus == StorageBus_USB)
4655 rc = PDMR3UsbDriverDetach(pUVM, pcszDevice, uInstance, uLUN,
4656 pszDriverDetach, 0 /* iOccurence */,
4657 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
4658 else
4659 rc = PDMR3DriverDetach(pUVM, pcszDevice, uInstance, uLUN,
4660 pszDriverDetach, 0 /* iOccurence */,
4661 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
4662
4663 if (pszDriverDetach)
4664 {
4665 RTStrFree(pszDriverDetach);
4666 /* Remove the complete node and create new for the new config. */
4667 CFGMR3RemoveNode(pLunL0);
4668 pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
4669 if (pLunL0)
4670 {
4671 try
4672 {
4673 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4674 }
4675 catch (ConfigError &x)
4676 {
4677 // InsertConfig threw something:
4678 return x.m_vrc;
4679 }
4680 }
4681 }
4682 if (rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4683 rc = VINF_SUCCESS;
4684 AssertRCReturn(rc, rc);
4685
4686 /*
4687 * Don't remove the LUN except for IDE/floppy/NVMe (which connects directly to the medium driver
4688 * even for DVD devices) or if there is a hotplug event which rips out the complete device.
4689 */
4690 if ( fHotplug
4691 || enmBus == StorageBus_IDE
4692 || enmBus == StorageBus_Floppy
4693 || enmBus == StorageBus_PCIe
4694 || (enmBus == StorageBus_SATA && enmDevType != DeviceType_DVD))
4695 {
4696 fAddLun = true;
4697 CFGMR3RemoveNode(pLunL0);
4698 }
4699 }
4700 else
4701 fAddLun = true;
4702
4703 try
4704 {
4705 if (fAddLun)
4706 InsertConfigNode(pCtlInst, Utf8StrFmt("LUN#%u", uLUN).c_str(), &pLunL0);
4707 }
4708 catch (ConfigError &x)
4709 {
4710 // InsertConfig threw something:
4711 return x.m_vrc;
4712 }
4713
4714 if (ppLunL0)
4715 *ppLunL0 = pLunL0;
4716
4717 return rc;
4718}
4719
4720int Console::i_configMediumAttachment(const char *pcszDevice,
4721 unsigned uInstance,
4722 StorageBus_T enmBus,
4723 bool fUseHostIOCache,
4724 bool fBuiltinIOCache,
4725 bool fInsertDiskIntegrityDrv,
4726 bool fSetupMerge,
4727 unsigned uMergeSource,
4728 unsigned uMergeTarget,
4729 IMediumAttachment *pMediumAtt,
4730 MachineState_T aMachineState,
4731 HRESULT *phrc,
4732 bool fAttachDetach,
4733 bool fForceUnmount,
4734 bool fHotplug,
4735 PUVM pUVM,
4736 DeviceType_T *paLedDevType,
4737 PCFGMNODE *ppLunL0)
4738{
4739 // InsertConfig* throws
4740 try
4741 {
4742 int rc = VINF_SUCCESS;
4743 HRESULT hrc;
4744 Bstr bstr;
4745 PCFGMNODE pCtlInst = NULL;
4746
4747// #define RC_CHECK() AssertMsgReturn(RT_SUCCESS(rc), ("rc=%Rrc\n", rc), rc)
4748#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4749
4750 LONG lDev;
4751 hrc = pMediumAtt->COMGETTER(Device)(&lDev); H();
4752 LONG lPort;
4753 hrc = pMediumAtt->COMGETTER(Port)(&lPort); H();
4754 DeviceType_T lType;
4755 hrc = pMediumAtt->COMGETTER(Type)(&lType); H();
4756 BOOL fNonRotational;
4757 hrc = pMediumAtt->COMGETTER(NonRotational)(&fNonRotational); H();
4758 BOOL fDiscard;
4759 hrc = pMediumAtt->COMGETTER(Discard)(&fDiscard); H();
4760
4761 if (lType == DeviceType_DVD)
4762 fInsertDiskIntegrityDrv = false;
4763
4764 unsigned uLUN;
4765 PCFGMNODE pLunL0 = NULL;
4766 hrc = Console::i_storageBusPortDeviceToLun(enmBus, lPort, lDev, uLUN); H();
4767
4768 /* Determine the base path for the device instance. */
4769 if (enmBus != StorageBus_USB)
4770 pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "Devices/%s/%u/", pcszDevice, uInstance);
4771 else
4772 {
4773 /* If we hotplug a USB device create a new CFGM tree. */
4774 if (!fHotplug)
4775 pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "USB/%s/", pcszDevice);
4776 else
4777 pCtlInst = CFGMR3CreateTree(pUVM);
4778 }
4779 AssertReturn(pCtlInst, VERR_INTERNAL_ERROR);
4780
4781 if (enmBus == StorageBus_USB)
4782 {
4783 PCFGMNODE pCfg = NULL;
4784
4785 /* Create correct instance. */
4786 if (!fHotplug)
4787 {
4788 if (!fAttachDetach)
4789 InsertConfigNode(pCtlInst, Utf8StrFmt("%d", lPort).c_str(), &pCtlInst);
4790 else
4791 pCtlInst = CFGMR3GetChildF(pCtlInst, "%d/", lPort);
4792 }
4793
4794 if (!fAttachDetach)
4795 InsertConfigNode(pCtlInst, "Config", &pCfg);
4796
4797 uInstance = lPort; /* Overwrite uInstance with the correct one. */
4798
4799 if (!fHotplug && !fAttachDetach)
4800 {
4801 char aszUuid[RTUUID_STR_LENGTH + 1];
4802 USBStorageDevice UsbMsd = USBStorageDevice();
4803
4804 memset(aszUuid, 0, sizeof(aszUuid));
4805 rc = RTUuidCreate(&UsbMsd.mUuid);
4806 AssertRCReturn(rc, rc);
4807 rc = RTUuidToStr(&UsbMsd.mUuid, aszUuid, sizeof(aszUuid));
4808 AssertRCReturn(rc, rc);
4809
4810 UsbMsd.iPort = uInstance;
4811
4812 InsertConfigString(pCtlInst, "UUID", aszUuid);
4813 mUSBStorageDevices.push_back(UsbMsd);
4814
4815 /** @todo No LED after hotplugging. */
4816 /* Attach the status driver */
4817 i_attachStatusDriver(pCtlInst, DeviceType_HardDisk, 0, 7, &paLedDevType,
4818 &mapMediumAttachments, pcszDevice, 0);
4819 }
4820 }
4821
4822 rc = i_removeMediumDriverFromVm(pCtlInst, pcszDevice, uInstance, uLUN, enmBus, fAttachDetach,
4823 fHotplug, fForceUnmount, pUVM, lType, &pLunL0);
4824 if (RT_FAILURE(rc))
4825 return rc;
4826 if (ppLunL0)
4827 *ppLunL0 = pLunL0;
4828
4829 Utf8Str devicePath = Utf8StrFmt("%s/%u/LUN#%u", pcszDevice, uInstance, uLUN);
4830 mapMediumAttachments[devicePath] = pMediumAtt;
4831
4832 ComPtr<IMedium> ptrMedium;
4833 hrc = pMediumAtt->COMGETTER(Medium)(ptrMedium.asOutParam()); H();
4834
4835 /*
4836 * 1. Only check this for hard disk images.
4837 * 2. Only check during VM creation and not later, especially not during
4838 * taking an online snapshot!
4839 */
4840 if ( lType == DeviceType_HardDisk
4841 && ( aMachineState == MachineState_Starting
4842 || aMachineState == MachineState_Restoring))
4843 {
4844 rc = i_checkMediumLocation(ptrMedium, &fUseHostIOCache);
4845 if (RT_FAILURE(rc))
4846 return rc;
4847 }
4848
4849 BOOL fPassthrough = FALSE;
4850 if (ptrMedium.isNotNull())
4851 {
4852 BOOL fHostDrive;
4853 hrc = ptrMedium->COMGETTER(HostDrive)(&fHostDrive); H();
4854 if ( ( lType == DeviceType_DVD
4855 || lType == DeviceType_Floppy)
4856 && !fHostDrive)
4857 {
4858 /*
4859 * Informative logging.
4860 */
4861 Bstr strFile;
4862 hrc = ptrMedium->COMGETTER(Location)(strFile.asOutParam()); H();
4863 Utf8Str utfFile = Utf8Str(strFile);
4864 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
4865 (void)RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
4866 LogRel(("File system of '%s' (%s) is %s\n",
4867 utfFile.c_str(), lType == DeviceType_DVD ? "DVD" : "Floppy",
4868 RTFsTypeName(enmFsTypeFile)));
4869 }
4870
4871 if (fHostDrive)
4872 {
4873 hrc = pMediumAtt->COMGETTER(Passthrough)(&fPassthrough); H();
4874 }
4875 }
4876
4877 ComObjPtr<IBandwidthGroup> pBwGroup;
4878 Bstr strBwGroup;
4879 hrc = pMediumAtt->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
4880
4881 if (!pBwGroup.isNull())
4882 {
4883 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
4884 }
4885
4886 /*
4887 * Insert the SCSI driver for hotplug events on the SCSI/USB based storage controllers
4888 * or for SATA if the new device is a CD/DVD drive.
4889 */
4890 if ( (fHotplug || !fAttachDetach)
4891 && ( (enmBus == StorageBus_SCSI || enmBus == StorageBus_SAS || enmBus == StorageBus_USB || enmBus == StorageBus_VirtioSCSI)
4892 || (enmBus == StorageBus_SATA && lType == DeviceType_DVD && !fPassthrough)))
4893 {
4894 InsertConfigString(pLunL0, "Driver", "SCSI");
4895 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4896 }
4897
4898 rc = i_configMedium(pLunL0,
4899 !!fPassthrough,
4900 lType,
4901 fUseHostIOCache,
4902 fBuiltinIOCache,
4903 fInsertDiskIntegrityDrv,
4904 fSetupMerge,
4905 uMergeSource,
4906 uMergeTarget,
4907 strBwGroup.isEmpty() ? NULL : Utf8Str(strBwGroup).c_str(),
4908 !!fDiscard,
4909 !!fNonRotational,
4910 ptrMedium,
4911 aMachineState,
4912 phrc);
4913 if (RT_FAILURE(rc))
4914 return rc;
4915
4916 if (fAttachDetach)
4917 {
4918 /* Attach the new driver. */
4919 if (enmBus == StorageBus_USB)
4920 {
4921 if (fHotplug)
4922 {
4923 USBStorageDevice UsbMsd = USBStorageDevice();
4924 RTUuidCreate(&UsbMsd.mUuid);
4925 UsbMsd.iPort = uInstance;
4926 rc = PDMR3UsbCreateEmulatedDevice(pUVM, pcszDevice, pCtlInst, &UsbMsd.mUuid, NULL);
4927 if (RT_SUCCESS(rc))
4928 mUSBStorageDevices.push_back(UsbMsd);
4929 }
4930 else
4931 rc = PDMR3UsbDriverAttach(pUVM, pcszDevice, uInstance, uLUN,
4932 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4933 }
4934 else if ( !fHotplug
4935 && ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI || enmBus == StorageBus_VirtioSCSI)
4936 || (enmBus == StorageBus_SATA && lType == DeviceType_DVD)))
4937 rc = PDMR3DriverAttach(pUVM, pcszDevice, uInstance, uLUN,
4938 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4939 else
4940 rc = PDMR3DeviceAttach(pUVM, pcszDevice, uInstance, uLUN,
4941 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4942 AssertRCReturn(rc, rc);
4943
4944 /*
4945 * Make the secret key helper interface known to the VD driver if it is attached,
4946 * so we can get notified about missing keys.
4947 */
4948 PPDMIBASE pIBase = NULL;
4949 rc = PDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "VD", &pIBase);
4950 if (RT_SUCCESS(rc) && pIBase)
4951 {
4952 PPDMIMEDIA pIMedium = (PPDMIMEDIA)pIBase->pfnQueryInterface(pIBase, PDMIMEDIA_IID);
4953 if (pIMedium)
4954 {
4955 rc = pIMedium->pfnSetSecKeyIf(pIMedium, mpIfSecKey, mpIfSecKeyHlp);
4956 Assert(RT_SUCCESS(rc) || rc == VERR_NOT_SUPPORTED);
4957 }
4958 }
4959
4960 /* There is no need to handle removable medium mounting, as we
4961 * unconditionally replace everthing including the block driver level.
4962 * This means the new medium will be picked up automatically. */
4963 }
4964
4965 if (paLedDevType)
4966 paLedDevType[uLUN] = lType;
4967
4968 /* Dump the changed LUN if possible, dump the complete device otherwise */
4969 if ( aMachineState != MachineState_Starting
4970 && aMachineState != MachineState_Restoring)
4971 CFGMR3Dump(pLunL0 ? pLunL0 : pCtlInst);
4972 }
4973 catch (ConfigError &x)
4974 {
4975 // InsertConfig threw something:
4976 return x.m_vrc;
4977 }
4978
4979#undef H
4980
4981 return VINF_SUCCESS;
4982}
4983
4984int Console::i_configMedium(PCFGMNODE pLunL0,
4985 bool fPassthrough,
4986 DeviceType_T enmType,
4987 bool fUseHostIOCache,
4988 bool fBuiltinIOCache,
4989 bool fInsertDiskIntegrityDrv,
4990 bool fSetupMerge,
4991 unsigned uMergeSource,
4992 unsigned uMergeTarget,
4993 const char *pcszBwGroup,
4994 bool fDiscard,
4995 bool fNonRotational,
4996 ComPtr<IMedium> ptrMedium,
4997 MachineState_T aMachineState,
4998 HRESULT *phrc)
4999{
5000 // InsertConfig* throws
5001 try
5002 {
5003 HRESULT hrc;
5004 Bstr bstr;
5005 PCFGMNODE pCfg = NULL;
5006
5007#define H() \
5008 AssertMsgReturnStmt(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), if (phrc) *phrc = hrc, Global::vboxStatusCodeFromCOM(hrc))
5009
5010
5011 BOOL fHostDrive = FALSE;
5012 MediumType_T mediumType = MediumType_Normal;
5013 if (ptrMedium.isNotNull())
5014 {
5015 hrc = ptrMedium->COMGETTER(HostDrive)(&fHostDrive); H();
5016 hrc = ptrMedium->COMGETTER(Type)(&mediumType); H();
5017 }
5018
5019 if (fHostDrive)
5020 {
5021 Assert(ptrMedium.isNotNull());
5022 if (enmType == DeviceType_DVD)
5023 {
5024 InsertConfigString(pLunL0, "Driver", "HostDVD");
5025 InsertConfigNode(pLunL0, "Config", &pCfg);
5026
5027 hrc = ptrMedium->COMGETTER(Location)(bstr.asOutParam()); H();
5028 InsertConfigString(pCfg, "Path", bstr);
5029
5030 InsertConfigInteger(pCfg, "Passthrough", fPassthrough);
5031 }
5032 else if (enmType == DeviceType_Floppy)
5033 {
5034 InsertConfigString(pLunL0, "Driver", "HostFloppy");
5035 InsertConfigNode(pLunL0, "Config", &pCfg);
5036
5037 hrc = ptrMedium->COMGETTER(Location)(bstr.asOutParam()); H();
5038 InsertConfigString(pCfg, "Path", bstr);
5039 }
5040 }
5041 else
5042 {
5043 if (fInsertDiskIntegrityDrv)
5044 {
5045 /*
5046 * The actual configuration is done through CFGM extra data
5047 * for each inserted driver separately.
5048 */
5049 InsertConfigString(pLunL0, "Driver", "DiskIntegrity");
5050 InsertConfigNode(pLunL0, "Config", &pCfg);
5051 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
5052 }
5053
5054 InsertConfigString(pLunL0, "Driver", "VD");
5055 InsertConfigNode(pLunL0, "Config", &pCfg);
5056 switch (enmType)
5057 {
5058 case DeviceType_DVD:
5059 InsertConfigString(pCfg, "Type", "DVD");
5060 InsertConfigInteger(pCfg, "Mountable", 1);
5061 break;
5062 case DeviceType_Floppy:
5063 InsertConfigString(pCfg, "Type", "Floppy 1.44");
5064 InsertConfigInteger(pCfg, "Mountable", 1);
5065 break;
5066 case DeviceType_HardDisk:
5067 default:
5068 InsertConfigString(pCfg, "Type", "HardDisk");
5069 InsertConfigInteger(pCfg, "Mountable", 0);
5070 }
5071
5072 if ( ptrMedium.isNotNull()
5073 && ( enmType == DeviceType_DVD
5074 || enmType == DeviceType_Floppy)
5075 )
5076 {
5077 // if this medium represents an ISO image and this image is inaccessible,
5078 // the ignore it instead of causing a failure; this can happen when we
5079 // restore a VM state and the ISO has disappeared, e.g. because the Guest
5080 // Additions were mounted and the user upgraded VirtualBox. Previously
5081 // we failed on startup, but that's not good because the only way out then
5082 // would be to discard the VM state...
5083 MediumState_T mediumState;
5084 hrc = ptrMedium->RefreshState(&mediumState); H();
5085 if (mediumState == MediumState_Inaccessible)
5086 {
5087 Bstr loc;
5088 hrc = ptrMedium->COMGETTER(Location)(loc.asOutParam()); H();
5089 i_atVMRuntimeErrorCallbackF(0, "DvdOrFloppyImageInaccessible",
5090 N_("The image file '%ls' is inaccessible and is being ignored. "
5091 "Please select a different image file for the virtual %s drive."),
5092 loc.raw(),
5093 enmType == DeviceType_DVD ? "DVD" : "floppy");
5094 ptrMedium.setNull();
5095 }
5096 }
5097
5098 if (ptrMedium.isNotNull())
5099 {
5100 /* Start with length of parent chain, as the list is reversed */
5101 unsigned uImage = 0;
5102 ComPtr<IMedium> ptrTmp = ptrMedium;
5103 while (ptrTmp.isNotNull())
5104 {
5105 uImage++;
5106 ComPtr<IMedium> ptrParent;
5107 hrc = ptrTmp->COMGETTER(Parent)(ptrParent.asOutParam()); H();
5108 ptrTmp = ptrParent;
5109 }
5110 /* Index of last image */
5111 uImage--;
5112
5113# ifdef VBOX_WITH_EXTPACK
5114 if (mptrExtPackManager->i_isExtPackUsable(ORACLE_PUEL_EXTPACK_NAME))
5115 {
5116 /* Configure loading the VDPlugin. */
5117 static const char s_szVDPlugin[] = "VDPluginCrypt";
5118 PCFGMNODE pCfgPlugins = NULL;
5119 PCFGMNODE pCfgPlugin = NULL;
5120 Utf8Str strPlugin;
5121 hrc = mptrExtPackManager->i_getLibraryPathForExtPack(s_szVDPlugin, ORACLE_PUEL_EXTPACK_NAME, &strPlugin);
5122 // Don't fail, this is optional!
5123 if (SUCCEEDED(hrc))
5124 {
5125 InsertConfigNode(pCfg, "Plugins", &pCfgPlugins);
5126 InsertConfigNode(pCfgPlugins, s_szVDPlugin, &pCfgPlugin);
5127 InsertConfigString(pCfgPlugin, "Path", strPlugin.c_str());
5128 }
5129 }
5130# endif
5131
5132 hrc = ptrMedium->COMGETTER(Location)(bstr.asOutParam()); H();
5133 InsertConfigString(pCfg, "Path", bstr);
5134
5135 hrc = ptrMedium->COMGETTER(Format)(bstr.asOutParam()); H();
5136 InsertConfigString(pCfg, "Format", bstr);
5137
5138 if (mediumType == MediumType_Readonly)
5139 InsertConfigInteger(pCfg, "ReadOnly", 1);
5140 else if (enmType == DeviceType_Floppy)
5141 InsertConfigInteger(pCfg, "MaybeReadOnly", 1);
5142
5143 /* Start without exclusive write access to the images. */
5144 /** @todo Live Migration: I don't quite like this, we risk screwing up when
5145 * we're resuming the VM if some 3rd dude have any of the VDIs open
5146 * with write sharing denied. However, if the two VMs are sharing a
5147 * image it really is necessary....
5148 *
5149 * So, on the "lock-media" command, the target teleporter should also
5150 * make DrvVD undo TempReadOnly. It gets interesting if we fail after
5151 * that. Grumble. */
5152 if ( enmType == DeviceType_HardDisk
5153 && aMachineState == MachineState_TeleportingIn)
5154 InsertConfigInteger(pCfg, "TempReadOnly", 1);
5155
5156 /* Flag for opening the medium for sharing between VMs. This
5157 * is done at the moment only for the first (and only) medium
5158 * in the chain, as shared media can have no diffs. */
5159 if (mediumType == MediumType_Shareable)
5160 InsertConfigInteger(pCfg, "Shareable", 1);
5161
5162 if (!fUseHostIOCache)
5163 {
5164 InsertConfigInteger(pCfg, "UseNewIo", 1);
5165 /*
5166 * Activate the builtin I/O cache for harddisks only.
5167 * It caches writes only which doesn't make sense for DVD drives
5168 * and just increases the overhead.
5169 */
5170 if ( fBuiltinIOCache
5171 && (enmType == DeviceType_HardDisk))
5172 InsertConfigInteger(pCfg, "BlockCache", 1);
5173 }
5174
5175 if (fSetupMerge)
5176 {
5177 InsertConfigInteger(pCfg, "SetupMerge", 1);
5178 if (uImage == uMergeSource)
5179 InsertConfigInteger(pCfg, "MergeSource", 1);
5180 else if (uImage == uMergeTarget)
5181 InsertConfigInteger(pCfg, "MergeTarget", 1);
5182 }
5183
5184 if (pcszBwGroup)
5185 InsertConfigString(pCfg, "BwGroup", pcszBwGroup);
5186
5187 if (fDiscard)
5188 InsertConfigInteger(pCfg, "Discard", 1);
5189
5190 if (fNonRotational)
5191 InsertConfigInteger(pCfg, "NonRotationalMedium", 1);
5192
5193 /* Pass all custom parameters. */
5194 bool fHostIP = true;
5195 bool fEncrypted = false;
5196 hrc = i_configMediumProperties(pCfg, ptrMedium, &fHostIP, &fEncrypted); H();
5197
5198 /* Create an inverted list of parents. */
5199 uImage--;
5200 ComPtr<IMedium> ptrParentMedium = ptrMedium;
5201 for (PCFGMNODE pParent = pCfg;; uImage--)
5202 {
5203 ComPtr<IMedium> ptrCurMedium;
5204 hrc = ptrParentMedium->COMGETTER(Parent)(ptrCurMedium.asOutParam()); H();
5205 if (ptrCurMedium.isNull())
5206 break;
5207
5208 PCFGMNODE pCur;
5209 InsertConfigNode(pParent, "Parent", &pCur);
5210 hrc = ptrCurMedium->COMGETTER(Location)(bstr.asOutParam()); H();
5211 InsertConfigString(pCur, "Path", bstr);
5212
5213 hrc = ptrCurMedium->COMGETTER(Format)(bstr.asOutParam()); H();
5214 InsertConfigString(pCur, "Format", bstr);
5215
5216 if (fSetupMerge)
5217 {
5218 if (uImage == uMergeSource)
5219 InsertConfigInteger(pCur, "MergeSource", 1);
5220 else if (uImage == uMergeTarget)
5221 InsertConfigInteger(pCur, "MergeTarget", 1);
5222 }
5223
5224 /* Configure medium properties. */
5225 hrc = i_configMediumProperties(pCur, ptrCurMedium, &fHostIP, &fEncrypted); H();
5226
5227 /* next */
5228 pParent = pCur;
5229 ptrParentMedium = ptrCurMedium;
5230 }
5231
5232 /* Custom code: put marker to not use host IP stack to driver
5233 * configuration node. Simplifies life of DrvVD a bit. */
5234 if (!fHostIP)
5235 InsertConfigInteger(pCfg, "HostIPStack", 0);
5236
5237 if (fEncrypted)
5238 m_cDisksEncrypted++;
5239 }
5240 else
5241 {
5242 /* Set empty drive flag for DVD or floppy without media. */
5243 if ( enmType == DeviceType_DVD
5244 || enmType == DeviceType_Floppy)
5245 InsertConfigInteger(pCfg, "EmptyDrive", 1);
5246 }
5247 }
5248#undef H
5249 }
5250 catch (ConfigError &x)
5251 {
5252 // InsertConfig threw something:
5253 return x.m_vrc;
5254 }
5255
5256 return VINF_SUCCESS;
5257}
5258
5259/**
5260 * Adds the medium properties to the CFGM tree.
5261 *
5262 * @returns VBox status code.
5263 * @param pCur The current CFGM node.
5264 * @param pMedium The medium object to configure.
5265 * @param pfHostIP Where to return the value of the \"HostIPStack\" property if found.
5266 * @param pfEncrypted Where to return whether the medium is encrypted.
5267 */
5268int Console::i_configMediumProperties(PCFGMNODE pCur, IMedium *pMedium, bool *pfHostIP, bool *pfEncrypted)
5269{
5270 /* Pass all custom parameters. */
5271 SafeArray<BSTR> aNames;
5272 SafeArray<BSTR> aValues;
5273 HRESULT hrc = pMedium->GetProperties(NULL, ComSafeArrayAsOutParam(aNames),
5274 ComSafeArrayAsOutParam(aValues));
5275
5276 if ( SUCCEEDED(hrc)
5277 && aNames.size() != 0)
5278 {
5279 PCFGMNODE pVDC;
5280 InsertConfigNode(pCur, "VDConfig", &pVDC);
5281 for (size_t ii = 0; ii < aNames.size(); ++ii)
5282 {
5283 if (aValues[ii] && *aValues[ii])
5284 {
5285 Utf8Str name = aNames[ii];
5286 Utf8Str value = aValues[ii];
5287 size_t offSlash = name.find("/", 0);
5288 if ( offSlash != name.npos
5289 && !name.startsWith("Special/"))
5290 {
5291 com::Utf8Str strFilter;
5292 com::Utf8Str strKey;
5293
5294 hrc = strFilter.assignEx(name, 0, offSlash);
5295 if (FAILED(hrc))
5296 break;
5297
5298 hrc = strKey.assignEx(name, offSlash + 1, name.length() - offSlash - 1); /* Skip slash */
5299 if (FAILED(hrc))
5300 break;
5301
5302 PCFGMNODE pCfgFilterConfig = CFGMR3GetChild(pVDC, strFilter.c_str());
5303 if (!pCfgFilterConfig)
5304 InsertConfigNode(pVDC, strFilter.c_str(), &pCfgFilterConfig);
5305
5306 InsertConfigString(pCfgFilterConfig, strKey.c_str(), value);
5307 }
5308 else
5309 {
5310 InsertConfigString(pVDC, name.c_str(), value);
5311 if ( name.compare("HostIPStack") == 0
5312 && value.compare("0") == 0)
5313 *pfHostIP = false;
5314 }
5315
5316 if ( name.compare("CRYPT/KeyId") == 0
5317 && pfEncrypted)
5318 *pfEncrypted = true;
5319 }
5320 }
5321 }
5322
5323 return hrc;
5324}
5325
5326
5327/**
5328 * Construct the Network configuration tree
5329 *
5330 * @returns VBox status code.
5331 *
5332 * @param pszDevice The PDM device name.
5333 * @param uInstance The PDM device instance.
5334 * @param uLun The PDM LUN number of the drive.
5335 * @param aNetworkAdapter The network adapter whose attachment needs to be changed
5336 * @param pCfg Configuration node for the device
5337 * @param pLunL0 To store the pointer to the LUN#0.
5338 * @param pInst The instance CFGM node
5339 * @param fAttachDetach To determine if the network attachment should
5340 * be attached/detached after/before
5341 * configuration.
5342 * @param fIgnoreConnectFailure
5343 * True if connection failures should be ignored
5344 * (makes only sense for bridged/host-only networks).
5345 *
5346 * @note Locks this object for writing.
5347 * @thread EMT
5348 */
5349int Console::i_configNetwork(const char *pszDevice,
5350 unsigned uInstance,
5351 unsigned uLun,
5352 INetworkAdapter *aNetworkAdapter,
5353 PCFGMNODE pCfg,
5354 PCFGMNODE pLunL0,
5355 PCFGMNODE pInst,
5356 bool fAttachDetach,
5357 bool fIgnoreConnectFailure)
5358{
5359 RT_NOREF(fIgnoreConnectFailure);
5360 AutoCaller autoCaller(this);
5361 AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED);
5362
5363 // InsertConfig* throws
5364 try
5365 {
5366 int rc = VINF_SUCCESS;
5367 HRESULT hrc;
5368 Bstr bstr;
5369
5370#ifdef VBOX_WITH_CLOUD_NET
5371 /* We'll need device's pCfg for cloud attachments */
5372 PCFGMNODE pDevCfg = pCfg;
5373#endif /* VBOX_WITH_CLOUD_NET */
5374
5375#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
5376
5377 /*
5378 * Locking the object before doing VMR3* calls is quite safe here, since
5379 * we're on EMT. Write lock is necessary because we indirectly modify the
5380 * meAttachmentType member.
5381 */
5382 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
5383
5384 ComPtr<IMachine> pMachine = i_machine();
5385
5386 ComPtr<IVirtualBox> virtualBox;
5387 hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam()); H();
5388
5389 ComPtr<IHost> host;
5390 hrc = virtualBox->COMGETTER(Host)(host.asOutParam()); H();
5391
5392 BOOL fSniffer;
5393 hrc = aNetworkAdapter->COMGETTER(TraceEnabled)(&fSniffer); H();
5394
5395 NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy;
5396 hrc = aNetworkAdapter->COMGETTER(PromiscModePolicy)(&enmPromiscModePolicy); H();
5397 const char *pszPromiscuousGuestPolicy;
5398 switch (enmPromiscModePolicy)
5399 {
5400 case NetworkAdapterPromiscModePolicy_Deny: pszPromiscuousGuestPolicy = "deny"; break;
5401 case NetworkAdapterPromiscModePolicy_AllowNetwork: pszPromiscuousGuestPolicy = "allow-network"; break;
5402 case NetworkAdapterPromiscModePolicy_AllowAll: pszPromiscuousGuestPolicy = "allow-all"; break;
5403 default: AssertFailedReturn(VERR_INTERNAL_ERROR_4);
5404 }
5405
5406 if (fAttachDetach)
5407 {
5408 rc = PDMR3DeviceDetach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/);
5409 if (rc == VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN)
5410 rc = VINF_SUCCESS;
5411 AssertLogRelRCReturn(rc, rc);
5412
5413 /* Nuke anything which might have been left behind. */
5414 CFGMR3RemoveNode(CFGMR3GetChildF(pInst, "LUN#%u", uLun));
5415 }
5416
5417 Bstr networkName, trunkName, trunkType;
5418 NetworkAttachmentType_T eAttachmentType;
5419 hrc = aNetworkAdapter->COMGETTER(AttachmentType)(&eAttachmentType); H();
5420
5421#ifdef VBOX_WITH_NETSHAPER
5422 ComObjPtr<IBandwidthGroup> pBwGroup;
5423 Bstr strBwGroup;
5424 hrc = aNetworkAdapter->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
5425
5426 if (!pBwGroup.isNull())
5427 {
5428 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
5429 }
5430#endif /* VBOX_WITH_NETSHAPER */
5431
5432 AssertMsg(uLun == 0, ("Network attachments with LUN > 0 are not supported yet\n"));
5433 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", uLun);
5434
5435 /*
5436 * Do not insert neither a shaper nor a sniffer if we are not attached to anything.
5437 * This way we can easily detect if we are attached to anything at the device level.
5438 */
5439#ifdef VBOX_WITH_NETSHAPER
5440 if (!strBwGroup.isEmpty() && eAttachmentType != NetworkAttachmentType_Null)
5441 {
5442 InsertConfigString(pLunL0, "Driver", "NetShaper");
5443 InsertConfigNode(pLunL0, "Config", &pCfg);
5444 InsertConfigString(pCfg, "BwGroup", strBwGroup);
5445 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
5446 }
5447#endif /* VBOX_WITH_NETSHAPER */
5448
5449 if (fSniffer && eAttachmentType != NetworkAttachmentType_Null)
5450 {
5451 InsertConfigString(pLunL0, "Driver", "NetSniffer");
5452 InsertConfigNode(pLunL0, "Config", &pCfg);
5453 hrc = aNetworkAdapter->COMGETTER(TraceFile)(bstr.asOutParam()); H();
5454 if (!bstr.isEmpty()) /* check convention for indicating default file. */
5455 InsertConfigString(pCfg, "File", bstr);
5456 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
5457 }
5458
5459 switch (eAttachmentType)
5460 {
5461 case NetworkAttachmentType_Null:
5462 break;
5463
5464 case NetworkAttachmentType_NAT:
5465 {
5466 ComPtr<INATEngine> natEngine;
5467 hrc = aNetworkAdapter->COMGETTER(NATEngine)(natEngine.asOutParam()); H();
5468 InsertConfigString(pLunL0, "Driver", "NAT");
5469 InsertConfigNode(pLunL0, "Config", &pCfg);
5470
5471 /* Configure TFTP prefix and boot filename. */
5472 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
5473 if (!bstr.isEmpty())
5474 InsertConfigString(pCfg, "TFTPPrefix", Utf8StrFmt("%ls%c%s", bstr.raw(), RTPATH_DELIMITER, "TFTP"));
5475 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
5476 InsertConfigString(pCfg, "BootFile", Utf8StrFmt("%ls.pxe", bstr.raw()));
5477
5478 hrc = natEngine->COMGETTER(Network)(bstr.asOutParam()); H();
5479 if (!bstr.isEmpty())
5480 InsertConfigString(pCfg, "Network", bstr);
5481 else
5482 {
5483 ULONG uSlot;
5484 hrc = aNetworkAdapter->COMGETTER(Slot)(&uSlot); H();
5485 InsertConfigString(pCfg, "Network", Utf8StrFmt("10.0.%d.0/24", uSlot+2));
5486 }
5487 hrc = natEngine->COMGETTER(HostIP)(bstr.asOutParam()); H();
5488 if (!bstr.isEmpty())
5489 InsertConfigString(pCfg, "BindIP", bstr);
5490 ULONG mtu = 0;
5491 ULONG sockSnd = 0;
5492 ULONG sockRcv = 0;
5493 ULONG tcpSnd = 0;
5494 ULONG tcpRcv = 0;
5495 hrc = natEngine->GetNetworkSettings(&mtu, &sockSnd, &sockRcv, &tcpSnd, &tcpRcv); H();
5496 if (mtu)
5497 InsertConfigInteger(pCfg, "SlirpMTU", mtu);
5498 if (sockRcv)
5499 InsertConfigInteger(pCfg, "SockRcv", sockRcv);
5500 if (sockSnd)
5501 InsertConfigInteger(pCfg, "SockSnd", sockSnd);
5502 if (tcpRcv)
5503 InsertConfigInteger(pCfg, "TcpRcv", tcpRcv);
5504 if (tcpSnd)
5505 InsertConfigInteger(pCfg, "TcpSnd", tcpSnd);
5506 hrc = natEngine->COMGETTER(TFTPPrefix)(bstr.asOutParam()); H();
5507 if (!bstr.isEmpty())
5508 {
5509 RemoveConfigValue(pCfg, "TFTPPrefix");
5510 InsertConfigString(pCfg, "TFTPPrefix", bstr);
5511 }
5512 hrc = natEngine->COMGETTER(TFTPBootFile)(bstr.asOutParam()); H();
5513 if (!bstr.isEmpty())
5514 {
5515 RemoveConfigValue(pCfg, "BootFile");
5516 InsertConfigString(pCfg, "BootFile", bstr);
5517 }
5518 hrc = natEngine->COMGETTER(TFTPNextServer)(bstr.asOutParam()); H();
5519 if (!bstr.isEmpty())
5520 InsertConfigString(pCfg, "NextServer", bstr);
5521 BOOL fDNSFlag;
5522 hrc = natEngine->COMGETTER(DNSPassDomain)(&fDNSFlag); H();
5523 InsertConfigInteger(pCfg, "PassDomain", fDNSFlag);
5524 hrc = natEngine->COMGETTER(DNSProxy)(&fDNSFlag); H();
5525 InsertConfigInteger(pCfg, "DNSProxy", fDNSFlag);
5526 hrc = natEngine->COMGETTER(DNSUseHostResolver)(&fDNSFlag); H();
5527 InsertConfigInteger(pCfg, "UseHostResolver", fDNSFlag);
5528
5529 ULONG aliasMode;
5530 hrc = natEngine->COMGETTER(AliasMode)(&aliasMode); H();
5531 InsertConfigInteger(pCfg, "AliasMode", aliasMode);
5532
5533 BOOL fLocalhostReachable;
5534 hrc = natEngine->COMGETTER(LocalhostReachable)(&fLocalhostReachable); H();
5535 InsertConfigInteger(pCfg, "LocalhostReachable", fLocalhostReachable);
5536
5537 /* port-forwarding */
5538 SafeArray<BSTR> pfs;
5539 hrc = natEngine->COMGETTER(Redirects)(ComSafeArrayAsOutParam(pfs)); H();
5540
5541 PCFGMNODE pPFTree = NULL;
5542 if (pfs.size() > 0)
5543 InsertConfigNode(pCfg, "PortForwarding", &pPFTree);
5544
5545 for (unsigned int i = 0; i < pfs.size(); ++i)
5546 {
5547 PCFGMNODE pPF = NULL; /* /Devices/Dev/.../Config/PortForwarding/$n/ */
5548
5549 uint16_t port = 0;
5550 Utf8Str utf = pfs[i];
5551 Utf8Str strName;
5552 Utf8Str strProto;
5553 Utf8Str strHostPort;
5554 Utf8Str strHostIP;
5555 Utf8Str strGuestPort;
5556 Utf8Str strGuestIP;
5557 size_t pos, ppos;
5558 pos = ppos = 0;
5559#define ITERATE_TO_NEXT_TERM(res, str, pos, ppos) \
5560 { \
5561 pos = str.find(",", ppos); \
5562 if (pos == Utf8Str::npos) \
5563 { \
5564 Log(( #res " extracting from %s is failed\n", str.c_str())); \
5565 continue; \
5566 } \
5567 res = str.substr(ppos, pos - ppos); \
5568 Log2((#res " %s pos:%d, ppos:%d\n", res.c_str(), pos, ppos)); \
5569 ppos = pos + 1; \
5570 } /* no do { ... } while because of 'continue' */
5571 ITERATE_TO_NEXT_TERM(strName, utf, pos, ppos);
5572 ITERATE_TO_NEXT_TERM(strProto, utf, pos, ppos);
5573 ITERATE_TO_NEXT_TERM(strHostIP, utf, pos, ppos);
5574 ITERATE_TO_NEXT_TERM(strHostPort, utf, pos, ppos);
5575 ITERATE_TO_NEXT_TERM(strGuestIP, utf, pos, ppos);
5576 strGuestPort = utf.substr(ppos, utf.length() - ppos);
5577#undef ITERATE_TO_NEXT_TERM
5578
5579 uint32_t proto = strProto.toUInt32();
5580 bool fValid = true;
5581 switch (proto)
5582 {
5583 case NATProtocol_UDP:
5584 strProto = "UDP";
5585 break;
5586 case NATProtocol_TCP:
5587 strProto = "TCP";
5588 break;
5589 default:
5590 fValid = false;
5591 }
5592 /* continue with next rule if no valid proto was passed */
5593 if (!fValid)
5594 continue;
5595
5596 InsertConfigNode(pPFTree, Utf8StrFmt("%u", i).c_str(), &pPF);
5597
5598 if (!strName.isEmpty())
5599 InsertConfigString(pPF, "Name", strName);
5600
5601 InsertConfigString(pPF, "Protocol", strProto);
5602
5603 if (!strHostIP.isEmpty())
5604 InsertConfigString(pPF, "BindIP", strHostIP);
5605
5606 if (!strGuestIP.isEmpty())
5607 InsertConfigString(pPF, "GuestIP", strGuestIP);
5608
5609 port = RTStrToUInt16(strHostPort.c_str());
5610 if (port)
5611 InsertConfigInteger(pPF, "HostPort", port);
5612
5613 port = RTStrToUInt16(strGuestPort.c_str());
5614 if (port)
5615 InsertConfigInteger(pPF, "GuestPort", port);
5616 }
5617 break;
5618 }
5619
5620 case NetworkAttachmentType_Bridged:
5621 {
5622#if (defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)) && !defined(VBOX_WITH_NETFLT)
5623 hrc = i_attachToTapInterface(aNetworkAdapter);
5624 if (FAILED(hrc))
5625 {
5626 switch (hrc)
5627 {
5628 case E_ACCESSDENIED:
5629 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5630 "Failed to open '/dev/net/tun' for read/write access. Please check the "
5631 "permissions of that node. Either run 'chmod 0666 /dev/net/tun' or "
5632 "change the group of that node and make yourself a member of that group. Make "
5633 "sure that these changes are permanent, especially if you are "
5634 "using udev"));
5635 default:
5636 AssertMsgFailed(("Could not attach to host interface! Bad!\n"));
5637 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5638 "Failed to initialize Host Interface Networking"));
5639 }
5640 }
5641
5642 Assert((intptr_t)maTapFD[uInstance] >= 0);
5643 if ((intptr_t)maTapFD[uInstance] >= 0)
5644 {
5645 InsertConfigString(pLunL0, "Driver", "HostInterface");
5646 InsertConfigNode(pLunL0, "Config", &pCfg);
5647 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
5648 }
5649
5650#elif defined(VBOX_WITH_NETFLT)
5651 /*
5652 * This is the new VBoxNetFlt+IntNet stuff.
5653 */
5654 Bstr BridgedIfName;
5655 hrc = aNetworkAdapter->COMGETTER(BridgedInterface)(BridgedIfName.asOutParam());
5656 if (FAILED(hrc))
5657 {
5658 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(BridgedInterface) failed, hrc (0x%x)\n", hrc));
5659 H();
5660 }
5661
5662 Utf8Str BridgedIfNameUtf8(BridgedIfName);
5663 const char *pszBridgedIfName = BridgedIfNameUtf8.c_str();
5664
5665 ComPtr<IHostNetworkInterface> hostInterface;
5666 hrc = host->FindHostNetworkInterfaceByName(BridgedIfName.raw(),
5667 hostInterface.asOutParam());
5668 if (!SUCCEEDED(hrc))
5669 {
5670 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: FindByName failed, rc=%Rhrc (0x%x)\n", hrc, hrc));
5671 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5672 N_("Nonexistent host networking interface, name '%ls'"),
5673 BridgedIfName.raw());
5674 }
5675
5676# if defined(RT_OS_DARWIN)
5677 /* The name is in the format 'ifX: long name', chop it off at the colon. */
5678 char szTrunk[INTNET_MAX_TRUNK_NAME];
5679 RTStrCopy(szTrunk, sizeof(szTrunk), pszBridgedIfName);
5680 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
5681// Quick fix for @bugref{5633}
5682// if (!pszColon)
5683// {
5684// /*
5685// * Dynamic changing of attachment causes an attempt to configure
5686// * network with invalid host adapter (as it is must be changed before
5687// * the attachment), calling Detach here will cause a deadlock.
5688// * See @bugref{4750}.
5689// * hrc = aNetworkAdapter->Detach(); H();
5690// */
5691// return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5692// N_("Malformed host interface networking name '%ls'"),
5693// BridgedIfName.raw());
5694// }
5695 if (pszColon)
5696 *pszColon = '\0';
5697 const char *pszTrunk = szTrunk;
5698
5699# elif defined(RT_OS_SOLARIS)
5700 /* The name is in the format 'ifX[:1] - long name, chop it off at space. */
5701 char szTrunk[256];
5702 strlcpy(szTrunk, pszBridgedIfName, sizeof(szTrunk));
5703 char *pszSpace = (char *)memchr(szTrunk, ' ', sizeof(szTrunk));
5704
5705 /*
5706 * Currently don't bother about malformed names here for the sake of people using
5707 * VBoxManage and setting only the NIC name from there. If there is a space we
5708 * chop it off and proceed, otherwise just use whatever we've got.
5709 */
5710 if (pszSpace)
5711 *pszSpace = '\0';
5712
5713 /* Chop it off at the colon (zone naming eg: e1000g:1 we need only the e1000g) */
5714 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
5715 if (pszColon)
5716 *pszColon = '\0';
5717
5718 const char *pszTrunk = szTrunk;
5719
5720# elif defined(RT_OS_WINDOWS)
5721 HostNetworkInterfaceType_T eIfType;
5722 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
5723 if (FAILED(hrc))
5724 {
5725 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
5726 H();
5727 }
5728
5729 if (eIfType != HostNetworkInterfaceType_Bridged)
5730 {
5731 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5732 N_("Interface ('%ls') is not a Bridged Adapter interface"),
5733 BridgedIfName.raw());
5734 }
5735
5736 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
5737 if (FAILED(hrc))
5738 {
5739 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
5740 H();
5741 }
5742 Guid hostIFGuid(bstr);
5743
5744 INetCfg *pNc;
5745 ComPtr<INetCfgComponent> pAdaptorComponent;
5746 LPWSTR pszApp;
5747
5748 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
5749 Assert(hrc == S_OK);
5750 if (hrc != S_OK)
5751 {
5752 LogRel(("NetworkAttachmentType_Bridged: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5753 H();
5754 }
5755
5756 /* get the adapter's INetCfgComponent*/
5757 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
5758 pAdaptorComponent.asOutParam());
5759 if (hrc != S_OK)
5760 {
5761 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5762 LogRel(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)\n", hrc));
5763 H();
5764 }
5765# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
5766 char szTrunkName[INTNET_MAX_TRUNK_NAME];
5767 char *pszTrunkName = szTrunkName;
5768 wchar_t * pswzBindName;
5769 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
5770 Assert(hrc == S_OK);
5771 if (hrc == S_OK)
5772 {
5773 int cwBindName = (int)wcslen(pswzBindName) + 1;
5774 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
5775 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
5776 {
5777 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
5778 pszTrunkName += cbFullBindNamePrefix-1;
5779 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
5780 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
5781 {
5782 DWORD err = GetLastError();
5783 hrc = HRESULT_FROM_WIN32(err);
5784 AssertMsgFailed(("hrc=%Rhrc %#x\n", hrc, hrc));
5785 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
5786 hrc, hrc, err));
5787 }
5788 }
5789 else
5790 {
5791 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: insufficient szTrunkName buffer space\n"));
5792 /** @todo set appropriate error code */
5793 hrc = E_FAIL;
5794 }
5795
5796 if (hrc != S_OK)
5797 {
5798 AssertFailed();
5799 CoTaskMemFree(pswzBindName);
5800 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5801 H();
5802 }
5803
5804 /* we're not freeing the bind name since we'll use it later for detecting wireless*/
5805 }
5806 else
5807 {
5808 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5809 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)",
5810 hrc));
5811 H();
5812 }
5813
5814 const char *pszTrunk = szTrunkName;
5815 /* we're not releasing the INetCfg stuff here since we use it later to figure out whether it is wireless */
5816
5817# elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
5818# if defined(RT_OS_FREEBSD)
5819 /*
5820 * If we bridge to a tap interface open it the `old' direct way.
5821 * This works and performs better than bridging a physical
5822 * interface via the current FreeBSD vboxnetflt implementation.
5823 */
5824 if (!strncmp(pszBridgedIfName, RT_STR_TUPLE("tap"))) {
5825 hrc = i_attachToTapInterface(aNetworkAdapter);
5826 if (FAILED(hrc))
5827 {
5828 switch (hrc)
5829 {
5830 case E_ACCESSDENIED:
5831 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5832 "Failed to open '/dev/%s' for read/write access. Please check the "
5833 "permissions of that node, and that the net.link.tap.user_open "
5834 "sysctl is set. Either run 'chmod 0666 /dev/%s' or "
5835 "change the group of that node to vboxusers and make yourself "
5836 "a member of that group. Make sure that these changes are permanent."),
5837 pszBridgedIfName, pszBridgedIfName);
5838 default:
5839 AssertMsgFailed(("Could not attach to tap interface! Bad!\n"));
5840 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5841 "Failed to initialize Host Interface Networking"));
5842 }
5843 }
5844
5845 Assert((intptr_t)maTapFD[uInstance] >= 0);
5846 if ((intptr_t)maTapFD[uInstance] >= 0)
5847 {
5848 InsertConfigString(pLunL0, "Driver", "HostInterface");
5849 InsertConfigNode(pLunL0, "Config", &pCfg);
5850 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
5851 }
5852 break;
5853 }
5854# endif
5855 /** @todo Check for malformed names. */
5856 const char *pszTrunk = pszBridgedIfName;
5857
5858 /* Issue a warning if the interface is down */
5859 {
5860 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
5861 if (iSock >= 0)
5862 {
5863 struct ifreq Req;
5864 RT_ZERO(Req);
5865 RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pszBridgedIfName);
5866 if (ioctl(iSock, SIOCGIFFLAGS, &Req) >= 0)
5867 if ((Req.ifr_flags & IFF_UP) == 0)
5868 i_atVMRuntimeErrorCallbackF(0, "BridgedInterfaceDown",
5869 N_("Bridged interface %s is down. Guest will not be able to use this interface"),
5870 pszBridgedIfName);
5871
5872 close(iSock);
5873 }
5874 }
5875
5876# else
5877# error "PORTME (VBOX_WITH_NETFLT)"
5878# endif
5879
5880# if defined(RT_OS_DARWIN) && defined(VBOX_WITH_VMNET)
5881 InsertConfigString(pLunL0, "Driver", "VMNet");
5882 InsertConfigNode(pLunL0, "Config", &pCfg);
5883 InsertConfigString(pCfg, "Trunk", pszTrunk);
5884 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
5885# else
5886 InsertConfigString(pLunL0, "Driver", "IntNet");
5887 InsertConfigNode(pLunL0, "Config", &pCfg);
5888 InsertConfigString(pCfg, "Trunk", pszTrunk);
5889 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
5890 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure);
5891 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5892 char szNetwork[INTNET_MAX_NETWORK_NAME];
5893
5894# if defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN)
5895 /*
5896 * 'pszTrunk' contains just the interface name required in ring-0, while 'pszBridgedIfName' contains
5897 * interface name + optional description. We must not pass any description to the VM as it can differ
5898 * for the same interface name, eg: "nge0 - ethernet" (GUI) vs "nge0" (VBoxManage).
5899 */
5900 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszTrunk);
5901# else
5902 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszBridgedIfName);
5903# endif
5904 InsertConfigString(pCfg, "Network", szNetwork);
5905 networkName = Bstr(szNetwork);
5906 trunkName = Bstr(pszTrunk);
5907 trunkType = Bstr(TRUNKTYPE_NETFLT);
5908
5909 BOOL fSharedMacOnWire = false;
5910 hrc = hostInterface->COMGETTER(Wireless)(&fSharedMacOnWire);
5911 if (FAILED(hrc))
5912 {
5913 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Wireless) failed, hrc (0x%x)\n", hrc));
5914 H();
5915 }
5916 else if (fSharedMacOnWire)
5917 {
5918 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5919 Log(("Set SharedMacOnWire\n"));
5920 }
5921
5922# if defined(RT_OS_SOLARIS)
5923# if 0 /* bird: this is a bit questionable and might cause more trouble than its worth. */
5924 /* Zone access restriction, don't allow snooping the global zone. */
5925 zoneid_t ZoneId = getzoneid();
5926 if (ZoneId != GLOBAL_ZONEID)
5927 {
5928 InsertConfigInteger(pCfg, "IgnoreAllPromisc", true);
5929 }
5930# endif
5931# endif
5932# endif
5933
5934#elif defined(RT_OS_WINDOWS) /* not defined NetFlt */
5935 /* NOTHING TO DO HERE */
5936#elif defined(RT_OS_LINUX)
5937/// @todo aleksey: is there anything to be done here?
5938#elif defined(RT_OS_FREEBSD)
5939/** @todo FreeBSD: Check out this later (HIF networking). */
5940#else
5941# error "Port me"
5942#endif
5943 break;
5944 }
5945
5946 case NetworkAttachmentType_Internal:
5947 {
5948 hrc = aNetworkAdapter->COMGETTER(InternalNetwork)(bstr.asOutParam()); H();
5949 if (!bstr.isEmpty())
5950 {
5951 InsertConfigString(pLunL0, "Driver", "IntNet");
5952 InsertConfigNode(pLunL0, "Config", &pCfg);
5953 InsertConfigString(pCfg, "Network", bstr);
5954 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
5955 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5956 networkName = bstr;
5957 trunkType = Bstr(TRUNKTYPE_WHATEVER);
5958 }
5959 break;
5960 }
5961
5962 case NetworkAttachmentType_HostOnly:
5963 {
5964 InsertConfigString(pLunL0, "Driver", "IntNet");
5965 InsertConfigNode(pLunL0, "Config", &pCfg);
5966
5967 Bstr HostOnlyName;
5968 hrc = aNetworkAdapter->COMGETTER(HostOnlyInterface)(HostOnlyName.asOutParam());
5969 if (FAILED(hrc))
5970 {
5971 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(HostOnlyInterface) failed, hrc (0x%x)\n", hrc));
5972 H();
5973 }
5974
5975 Utf8Str HostOnlyNameUtf8(HostOnlyName);
5976 const char *pszHostOnlyName = HostOnlyNameUtf8.c_str();
5977#ifdef VBOX_WITH_VMNET
5978 /* Check if the matching host-only network has already been created. */
5979 Bstr bstrLowerIP, bstrUpperIP, bstrNetworkMask;
5980 BstrFmt bstrNetworkName("Legacy %s Network", pszHostOnlyName);
5981 ComPtr<IHostOnlyNetwork> hostOnlyNetwork;
5982 hrc = virtualBox->FindHostOnlyNetworkByName(bstrNetworkName.raw(), hostOnlyNetwork.asOutParam());
5983 if (FAILED(hrc))
5984 {
5985 /*
5986 * With VMNET there is no VBoxNetAdp to create vboxnetX adapters,
5987 * which means that the Host object won't be able to re-create
5988 * them from extra data. Go through existing DHCP/adapter config
5989 * to derive the parameters for the new network.
5990 */
5991 BstrFmt bstrOldNetworkName("HostInterfaceNetworking-%s", pszHostOnlyName);
5992 ComPtr<IDHCPServer> dhcpServer;
5993 hrc = virtualBox->FindDHCPServerByNetworkName(bstrOldNetworkName.raw(),
5994 dhcpServer.asOutParam());
5995 if (SUCCEEDED(hrc))
5996 {
5997 /* There is a DHCP server available for this network. */
5998 hrc = dhcpServer->COMGETTER(LowerIP)(bstrLowerIP.asOutParam());
5999 if (FAILED(hrc))
6000 {
6001 LogRel(("Console::i_configNetwork: COMGETTER(LowerIP) failed, hrc (%Rhrc)\n", hrc));
6002 H();
6003 }
6004 hrc = dhcpServer->COMGETTER(UpperIP)(bstrUpperIP.asOutParam());
6005 if (FAILED(hrc))
6006 {
6007 LogRel(("Console::i_configNetwork: COMGETTER(UpperIP) failed, hrc (%Rhrc)\n", hrc));
6008 H();
6009 }
6010 hrc = dhcpServer->COMGETTER(NetworkMask)(bstrNetworkMask.asOutParam());
6011 if (FAILED(hrc))
6012 {
6013 LogRel(("Console::i_configNetwork: COMGETTER(NetworkMask) failed, hrc (%Rhrc)\n", hrc));
6014 H();
6015 }
6016 }
6017 else
6018 {
6019 /* No DHCP server for this hostonly interface, let's look at extra data */
6020 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPAddress",
6021 pszHostOnlyName).raw(),
6022 bstrLowerIP.asOutParam());
6023 if (SUCCEEDED(hrc) && !bstrLowerIP.isEmpty())
6024 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPNetMask",
6025 pszHostOnlyName).raw(),
6026 bstrNetworkMask.asOutParam());
6027
6028 }
6029 RTNETADDRIPV4 ipAddr, ipMask;
6030 rc = bstrLowerIP.isEmpty() ? VERR_MISSING : RTNetStrToIPv4Addr(Utf8Str(bstrLowerIP).c_str(), &ipAddr);
6031 if (RT_FAILURE(rc))
6032 {
6033 /* We failed to locate any valid config of this vboxnetX interface, assume defaults. */
6034 LogRel(("NetworkAttachmentType_HostOnly: Invalid or missing lower IP '%ls', using '%ls' instead.\n",
6035 bstrLowerIP.raw(), getDefaultIPv4Address(Bstr(pszHostOnlyName)).raw()));
6036 bstrLowerIP = getDefaultIPv4Address(Bstr(pszHostOnlyName));
6037 bstrNetworkMask.setNull();
6038 bstrUpperIP.setNull();
6039 rc = RTNetStrToIPv4Addr(Utf8Str(bstrLowerIP).c_str(), &ipAddr);
6040 AssertLogRelMsgReturn(RT_SUCCESS(rc), ("RTNetStrToIPv4Addr(%ls) failed, rc=%Rrc\n", bstrLowerIP.raw(), rc),
6041 VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
6042 }
6043 rc = bstrNetworkMask.isEmpty() ? VERR_MISSING : RTNetStrToIPv4Addr(Utf8Str(bstrNetworkMask).c_str(), &ipMask);
6044 if (RT_FAILURE(rc))
6045 {
6046 LogRel(("NetworkAttachmentType_HostOnly: Invalid or missing network mask '%ls', using '%s' instead.\n",
6047 bstrNetworkMask.raw(), VBOXNET_IPV4MASK_DEFAULT));
6048 bstrNetworkMask = VBOXNET_IPV4MASK_DEFAULT;
6049 rc = RTNetStrToIPv4Addr(Utf8Str(bstrNetworkMask).c_str(), &ipMask);
6050 AssertLogRelMsgReturn(RT_SUCCESS(rc), ("RTNetStrToIPv4Addr(%ls) failed, rc=%Rrc\n", bstrNetworkMask.raw(), rc),
6051 VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
6052 }
6053 rc = bstrUpperIP.isEmpty() ? VERR_MISSING : RTNetStrToIPv4Addr(Utf8Str(bstrUpperIP).c_str(), &ipAddr);
6054 if (RT_FAILURE(rc))
6055 {
6056 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? */
6057 LogRel(("NetworkAttachmentType_HostOnly: Invalid or missing upper IP '%ls', using '%RTnaipv4' instead.\n",
6058 bstrUpperIP.raw(), ipAddr));
6059 bstrUpperIP = BstrFmt("%RTnaipv4", ipAddr);
6060 }
6061
6062 /* All parameters are set, create the new network. */
6063 hrc = virtualBox->CreateHostOnlyNetwork(bstrNetworkName.raw(), hostOnlyNetwork.asOutParam());
6064 if (FAILED(hrc))
6065 {
6066 LogRel(("NetworkAttachmentType_HostOnly: failed to create host-only network, hrc (0x%x)\n", hrc));
6067 H();
6068 }
6069 hrc = hostOnlyNetwork->COMSETTER(NetworkMask)(bstrNetworkMask.raw());
6070 if (FAILED(hrc))
6071 {
6072 LogRel(("NetworkAttachmentType_HostOnly: COMSETTER(NetworkMask) failed, hrc (0x%x)\n", hrc));
6073 H();
6074 }
6075 hrc = hostOnlyNetwork->COMSETTER(LowerIP)(bstrLowerIP.raw());
6076 if (FAILED(hrc))
6077 {
6078 LogRel(("NetworkAttachmentType_HostOnly: COMSETTER(LowerIP) failed, hrc (0x%x)\n", hrc));
6079 H();
6080 }
6081 hrc = hostOnlyNetwork->COMSETTER(UpperIP)(bstrUpperIP.raw());
6082 if (FAILED(hrc))
6083 {
6084 LogRel(("NetworkAttachmentType_HostOnly: COMSETTER(UpperIP) failed, hrc (0x%x)\n", hrc));
6085 H();
6086 }
6087 LogRel(("Console: created host-only network '%ls' with mask '%ls' and range '%ls'-'%ls'\n",
6088 bstrNetworkName.raw(), bstrNetworkMask.raw(), bstrLowerIP.raw(), bstrUpperIP.raw()));
6089 }
6090 else
6091 {
6092 /* The matching host-only network already exists. Tell the user to switch to it. */
6093 hrc = hostOnlyNetwork->COMGETTER(NetworkMask)(bstrNetworkMask.asOutParam());
6094 if (FAILED(hrc))
6095 {
6096 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(NetworkMask) failed, hrc (0x%x)\n", hrc));
6097 H();
6098 }
6099 hrc = hostOnlyNetwork->COMGETTER(LowerIP)(bstrLowerIP.asOutParam());
6100 if (FAILED(hrc))
6101 {
6102 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(LowerIP) failed, hrc (0x%x)\n", hrc));
6103 H();
6104 }
6105 hrc = hostOnlyNetwork->COMGETTER(UpperIP)(bstrUpperIP.asOutParam());
6106 if (FAILED(hrc))
6107 {
6108 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(UpperIP) failed, hrc (0x%x)\n", hrc));
6109 H();
6110 }
6111 }
6112 return VMSetError(VMR3GetVM(mpUVM), VERR_NOT_FOUND, RT_SRC_POS,
6113 N_("Host-only adapters are no longer supported!\n"
6114 "For your convenience a host-only network named '%ls' has been "
6115 "created with network mask '%ls' and IP address range '%ls' - '%ls'.\n"
6116 "To fix this problem, switch to 'Host-only Network' "
6117 "attachment type in the VM settings.\n"),
6118 bstrNetworkName.raw(), bstrNetworkMask.raw(),
6119 bstrLowerIP.raw(), bstrUpperIP.raw());
6120#endif /* VBOX_WITH_VMNET */
6121 ComPtr<IHostNetworkInterface> hostInterface;
6122 rc = host->FindHostNetworkInterfaceByName(HostOnlyName.raw(),
6123 hostInterface.asOutParam());
6124 if (!SUCCEEDED(rc))
6125 {
6126 LogRel(("NetworkAttachmentType_HostOnly: FindByName failed, rc (0x%x)\n", rc));
6127 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
6128 N_("Nonexistent host networking interface, name '%ls'"),
6129 HostOnlyName.raw());
6130 }
6131
6132 char szNetwork[INTNET_MAX_NETWORK_NAME];
6133 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszHostOnlyName);
6134
6135#if defined(RT_OS_WINDOWS)
6136# ifndef VBOX_WITH_NETFLT
6137 hrc = E_NOTIMPL;
6138 LogRel(("NetworkAttachmentType_HostOnly: Not Implemented\n"));
6139 H();
6140# else /* defined VBOX_WITH_NETFLT*/
6141 /** @todo r=bird: Put this in a function. */
6142
6143 HostNetworkInterfaceType_T eIfType;
6144 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
6145 if (FAILED(hrc))
6146 {
6147 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
6148 H();
6149 }
6150
6151 if (eIfType != HostNetworkInterfaceType_HostOnly)
6152 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
6153 N_("Interface ('%ls') is not a Host-Only Adapter interface"),
6154 HostOnlyName.raw());
6155
6156 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
6157 if (FAILED(hrc))
6158 {
6159 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
6160 H();
6161 }
6162 Guid hostIFGuid(bstr);
6163
6164 INetCfg *pNc;
6165 ComPtr<INetCfgComponent> pAdaptorComponent;
6166 LPWSTR pszApp;
6167 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
6168 Assert(hrc == S_OK);
6169 if (hrc != S_OK)
6170 {
6171 LogRel(("NetworkAttachmentType_HostOnly: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
6172 H();
6173 }
6174
6175 /* get the adapter's INetCfgComponent*/
6176 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
6177 pAdaptorComponent.asOutParam());
6178 if (hrc != S_OK)
6179 {
6180 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
6181 LogRel(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n", hrc, hrc));
6182 H();
6183 }
6184# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
6185 char szTrunkName[INTNET_MAX_TRUNK_NAME];
6186 bool fNdis6 = false;
6187 wchar_t * pwszHelpText;
6188 hrc = pAdaptorComponent->GetHelpText(&pwszHelpText);
6189 Assert(hrc == S_OK);
6190 if (hrc == S_OK)
6191 {
6192 Log(("help-text=%ls\n", pwszHelpText));
6193 if (!wcscmp(pwszHelpText, L"VirtualBox NDIS 6.0 Miniport Driver"))
6194 fNdis6 = true;
6195 CoTaskMemFree(pwszHelpText);
6196 }
6197 if (fNdis6)
6198 {
6199 strncpy(szTrunkName, pszHostOnlyName, sizeof(szTrunkName) - 1);
6200 Log(("trunk=%s\n", szTrunkName));
6201 }
6202 else
6203 {
6204 char *pszTrunkName = szTrunkName;
6205 wchar_t * pswzBindName;
6206 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
6207 Assert(hrc == S_OK);
6208 if (hrc == S_OK)
6209 {
6210 int cwBindName = (int)wcslen(pswzBindName) + 1;
6211 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
6212 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
6213 {
6214 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
6215 pszTrunkName += cbFullBindNamePrefix-1;
6216 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
6217 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
6218 {
6219 DWORD err = GetLastError();
6220 hrc = HRESULT_FROM_WIN32(err);
6221 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
6222 hrc, hrc, err));
6223 }
6224 }
6225 else
6226 {
6227 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: insufficient szTrunkName buffer space\n"));
6228 /** @todo set appropriate error code */
6229 hrc = E_FAIL;
6230 }
6231
6232 if (hrc != S_OK)
6233 {
6234 AssertFailed();
6235 CoTaskMemFree(pswzBindName);
6236 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
6237 H();
6238 }
6239 }
6240 else
6241 {
6242 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
6243 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n",
6244 hrc, hrc));
6245 H();
6246 }
6247
6248
6249 CoTaskMemFree(pswzBindName);
6250 }
6251
6252 trunkType = TRUNKTYPE_NETADP;
6253 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
6254
6255 pAdaptorComponent.setNull();
6256 /* release the pNc finally */
6257 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
6258
6259 const char *pszTrunk = szTrunkName;
6260
6261 InsertConfigString(pCfg, "Trunk", pszTrunk);
6262 InsertConfigString(pCfg, "Network", szNetwork);
6263 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure); /** @todo why is this
6264 windows only?? */
6265 networkName = Bstr(szNetwork);
6266 trunkName = Bstr(pszTrunk);
6267# endif /* defined VBOX_WITH_NETFLT*/
6268#elif defined(RT_OS_DARWIN)
6269 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
6270 InsertConfigString(pCfg, "Network", szNetwork);
6271 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
6272 networkName = Bstr(szNetwork);
6273 trunkName = Bstr(pszHostOnlyName);
6274 trunkType = TRUNKTYPE_NETADP;
6275#else
6276 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
6277 InsertConfigString(pCfg, "Network", szNetwork);
6278 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
6279 networkName = Bstr(szNetwork);
6280 trunkName = Bstr(pszHostOnlyName);
6281 trunkType = TRUNKTYPE_NETFLT;
6282#endif
6283 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
6284
6285#if !defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
6286
6287 Bstr tmpAddr, tmpMask;
6288
6289 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPAddress",
6290 pszHostOnlyName).raw(),
6291 tmpAddr.asOutParam());
6292 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty())
6293 {
6294 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPNetMask",
6295 pszHostOnlyName).raw(),
6296 tmpMask.asOutParam());
6297 if (SUCCEEDED(hrc) && !tmpMask.isEmpty())
6298 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
6299 tmpMask.raw());
6300 else
6301 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
6302 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
6303 }
6304 else
6305 {
6306 /* Grab the IP number from the 'vboxnetX' instance number (see netif.h) */
6307 hrc = hostInterface->EnableStaticIPConfig(getDefaultIPv4Address(Bstr(pszHostOnlyName)).raw(),
6308 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
6309 }
6310
6311 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
6312
6313 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6Address",
6314 pszHostOnlyName).raw(),
6315 tmpAddr.asOutParam());
6316 if (SUCCEEDED(hrc))
6317 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6NetMask", pszHostOnlyName).raw(),
6318 tmpMask.asOutParam());
6319 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty() && !tmpMask.isEmpty())
6320 {
6321 hrc = hostInterface->EnableStaticIPConfigV6(tmpAddr.raw(),
6322 Utf8Str(tmpMask).toUInt32());
6323 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
6324 }
6325#endif
6326 break;
6327 }
6328
6329 case NetworkAttachmentType_Generic:
6330 {
6331 hrc = aNetworkAdapter->COMGETTER(GenericDriver)(bstr.asOutParam()); H();
6332 SafeArray<BSTR> names;
6333 SafeArray<BSTR> values;
6334 hrc = aNetworkAdapter->GetProperties(Bstr().raw(),
6335 ComSafeArrayAsOutParam(names),
6336 ComSafeArrayAsOutParam(values)); H();
6337
6338 InsertConfigString(pLunL0, "Driver", bstr);
6339 InsertConfigNode(pLunL0, "Config", &pCfg);
6340 for (size_t ii = 0; ii < names.size(); ++ii)
6341 {
6342 if (values[ii] && *values[ii])
6343 {
6344 Utf8Str name = names[ii];
6345 Utf8Str value = values[ii];
6346 InsertConfigString(pCfg, name.c_str(), value);
6347 }
6348 }
6349 break;
6350 }
6351
6352 case NetworkAttachmentType_NATNetwork:
6353 {
6354 hrc = aNetworkAdapter->COMGETTER(NATNetwork)(bstr.asOutParam()); H();
6355 if (!bstr.isEmpty())
6356 {
6357 /** @todo add intnet prefix to separate namespaces, and add trunk if dealing with vboxnatX */
6358 InsertConfigString(pLunL0, "Driver", "IntNet");
6359 InsertConfigNode(pLunL0, "Config", &pCfg);
6360 InsertConfigString(pCfg, "Network", bstr);
6361 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
6362 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
6363 networkName = bstr;
6364 trunkType = Bstr(TRUNKTYPE_WHATEVER);
6365 }
6366 break;
6367 }
6368
6369#ifdef VBOX_WITH_CLOUD_NET
6370 case NetworkAttachmentType_Cloud:
6371 {
6372 static const char *s_pszCloudExtPackName = "Oracle VM VirtualBox Extension Pack";
6373 /*
6374 * Cloud network attachments do not work wihout installed extpack.
6375 * Without extpack support they won't work either.
6376 */
6377# ifdef VBOX_WITH_EXTPACK
6378 if (!mptrExtPackManager->i_isExtPackUsable(s_pszCloudExtPackName))
6379# endif
6380 {
6381 return VMSetError(VMR3GetVM(mpUVM), VERR_NOT_FOUND, RT_SRC_POS,
6382 N_("Implementation of the cloud network attachment not found!\n"
6383 "To fix this problem, either install the '%s' or switch to "
6384 "another network attachment type in the VM settings.\n"
6385 ),
6386 s_pszCloudExtPackName);
6387 }
6388
6389 ComPtr<ICloudNetwork> network;
6390 hrc = aNetworkAdapter->COMGETTER(CloudNetwork)(bstr.asOutParam()); H();
6391 hrc = pMachine->COMGETTER(Name)(mGateways.mTargetVM.asOutParam()); H();
6392 hrc = virtualBox->FindCloudNetworkByName(bstr.raw(), network.asOutParam()); H();
6393 hrc = startGateways(virtualBox, network, mGateways); H();
6394 InsertConfigBytes(pDevCfg, "MAC", &mGateways.mCloudMacAddress, sizeof(mGateways.mCloudMacAddress));
6395 if (!bstr.isEmpty())
6396 {
6397 InsertConfigString(pLunL0, "Driver", "IntNet");
6398 InsertConfigNode(pLunL0, "Config", &pCfg);
6399 InsertConfigString(pCfg, "Network", BstrFmt("cloud-%ls", bstr.raw()));
6400 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
6401 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
6402 networkName = bstr;
6403 trunkType = Bstr(TRUNKTYPE_WHATEVER);
6404 }
6405 break;
6406 }
6407#endif /* VBOX_WITH_CLOUD_NET */
6408
6409#ifdef VBOX_WITH_VMNET
6410 case NetworkAttachmentType_HostOnlyNetwork:
6411 {
6412 Bstr bstrId, bstrNetMask, bstrLowerIP, bstrUpperIP;
6413 ComPtr<IHostOnlyNetwork> network;
6414 hrc = aNetworkAdapter->COMGETTER(HostOnlyNetwork)(bstr.asOutParam()); H();
6415 hrc = virtualBox->FindHostOnlyNetworkByName(bstr.raw(), network.asOutParam());
6416 if (FAILED(hrc))
6417 {
6418 LogRel(("NetworkAttachmentType_HostOnlyNetwork: FindByName failed, hrc (0x%x)\n", hrc));
6419 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
6420 N_("Nonexistent host-only network '%ls'"),
6421 bstr.raw());
6422 }
6423 hrc = network->COMGETTER(Id)(bstrId.asOutParam()); H();
6424 hrc = network->COMGETTER(NetworkMask)(bstrNetMask.asOutParam()); H();
6425 hrc = network->COMGETTER(LowerIP)(bstrLowerIP.asOutParam()); H();
6426 hrc = network->COMGETTER(UpperIP)(bstrUpperIP.asOutParam()); H();
6427 if (!bstr.isEmpty())
6428 {
6429 InsertConfigString(pLunL0, "Driver", "VMNet");
6430 InsertConfigNode(pLunL0, "Config", &pCfg);
6431 // InsertConfigString(pCfg, "Trunk", Utf8Str(bstr).c_str());
6432 // InsertConfigString(pCfg, "Network", BstrFmt("HostOnlyNetworking-%ls", bstr.raw()));
6433 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
6434 InsertConfigString(pCfg, "Id", Utf8Str(bstrId).c_str());
6435 InsertConfigString(pCfg, "NetworkMask", Utf8Str(bstrNetMask).c_str());
6436 InsertConfigString(pCfg, "LowerIP", Utf8Str(bstrLowerIP).c_str());
6437 InsertConfigString(pCfg, "UpperIP", Utf8Str(bstrUpperIP).c_str());
6438 // InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
6439 networkName.setNull(); // We do not want DHCP server on our network!
6440 // trunkType = Bstr(TRUNKTYPE_WHATEVER);
6441 }
6442 break;
6443 }
6444#endif /* VBOX_WITH_VMNET */
6445
6446 default:
6447 AssertMsgFailed(("should not get here!\n"));
6448 break;
6449 }
6450
6451 /*
6452 * Attempt to attach the driver.
6453 */
6454 switch (eAttachmentType)
6455 {
6456 case NetworkAttachmentType_Null:
6457 break;
6458
6459 case NetworkAttachmentType_Bridged:
6460 case NetworkAttachmentType_Internal:
6461 case NetworkAttachmentType_HostOnly:
6462#ifdef VBOX_WITH_VMNET
6463 case NetworkAttachmentType_HostOnlyNetwork:
6464#endif /* VBOX_WITH_VMNET */
6465 case NetworkAttachmentType_NAT:
6466 case NetworkAttachmentType_Generic:
6467 case NetworkAttachmentType_NATNetwork:
6468#ifdef VBOX_WITH_CLOUD_NET
6469 case NetworkAttachmentType_Cloud:
6470#endif /* VBOX_WITH_CLOUD_NET */
6471 {
6472 if (SUCCEEDED(hrc) && RT_SUCCESS(rc))
6473 {
6474 if (fAttachDetach)
6475 {
6476 rc = PDMR3DriverAttach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/, NULL /* ppBase */);
6477 //AssertRC(rc);
6478 }
6479
6480 {
6481 /** @todo pritesh: get the dhcp server name from the
6482 * previous network configuration and then stop the server
6483 * else it may conflict with the dhcp server running with
6484 * the current attachment type
6485 */
6486 /* Stop the hostonly DHCP Server */
6487 }
6488
6489 /*
6490 * NAT networks start their DHCP server theirself, see NATNetwork::Start()
6491 */
6492 if ( !networkName.isEmpty()
6493 && eAttachmentType != NetworkAttachmentType_NATNetwork)
6494 {
6495 /*
6496 * Until we implement service reference counters DHCP Server will be stopped
6497 * by DHCPServerRunner destructor.
6498 */
6499 ComPtr<IDHCPServer> dhcpServer;
6500 hrc = virtualBox->FindDHCPServerByNetworkName(networkName.raw(),
6501 dhcpServer.asOutParam());
6502 if (SUCCEEDED(hrc))
6503 {
6504 /* there is a DHCP server available for this network */
6505 BOOL fEnabledDhcp;
6506 hrc = dhcpServer->COMGETTER(Enabled)(&fEnabledDhcp);
6507 if (FAILED(hrc))
6508 {
6509 LogRel(("DHCP svr: COMGETTER(Enabled) failed, hrc (%Rhrc)\n", hrc));
6510 H();
6511 }
6512
6513 if (fEnabledDhcp)
6514 hrc = dhcpServer->Start(trunkName.raw(),
6515 trunkType.raw());
6516 }
6517 else
6518 hrc = S_OK;
6519 }
6520 }
6521
6522 break;
6523 }
6524
6525 default:
6526 AssertMsgFailed(("should not get here!\n"));
6527 break;
6528 }
6529
6530 meAttachmentType[uInstance] = eAttachmentType;
6531 }
6532 catch (ConfigError &x)
6533 {
6534 // InsertConfig threw something:
6535 return x.m_vrc;
6536 }
6537
6538#undef H
6539
6540 return VINF_SUCCESS;
6541}
6542
6543
6544/**
6545 * Configures the serial port at the given CFGM node with the supplied parameters.
6546 *
6547 * @returns VBox status code.
6548 * @param pInst The instance CFGM node.
6549 * @param ePortMode The port mode to sue.
6550 * @param pszPath The serial port path.
6551 * @param fServer Flag whether the port should act as a server
6552 * for the pipe and TCP mode or connect as a client.
6553 */
6554int Console::i_configSerialPort(PCFGMNODE pInst, PortMode_T ePortMode, const char *pszPath, bool fServer)
6555{
6556 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
6557 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */
6558 PCFGMNODE pLunL1Cfg = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/Config */
6559
6560 try
6561 {
6562 InsertConfigNode(pInst, "LUN#0", &pLunL0);
6563 if (ePortMode == PortMode_HostPipe)
6564 {
6565 InsertConfigString(pLunL0, "Driver", "Char");
6566 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
6567 InsertConfigString(pLunL1, "Driver", "NamedPipe");
6568 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
6569 InsertConfigString(pLunL1Cfg, "Location", pszPath);
6570 InsertConfigInteger(pLunL1Cfg, "IsServer", fServer);
6571 }
6572 else if (ePortMode == PortMode_HostDevice)
6573 {
6574 InsertConfigString(pLunL0, "Driver", "Host Serial");
6575 InsertConfigNode(pLunL0, "Config", &pLunL1);
6576 InsertConfigString(pLunL1, "DevicePath", pszPath);
6577 }
6578 else if (ePortMode == PortMode_TCP)
6579 {
6580 InsertConfigString(pLunL0, "Driver", "Char");
6581 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
6582 InsertConfigString(pLunL1, "Driver", "TCP");
6583 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
6584 InsertConfigString(pLunL1Cfg, "Location", pszPath);
6585 InsertConfigInteger(pLunL1Cfg, "IsServer", fServer);
6586 }
6587 else if (ePortMode == PortMode_RawFile)
6588 {
6589 InsertConfigString(pLunL0, "Driver", "Char");
6590 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
6591 InsertConfigString(pLunL1, "Driver", "RawFile");
6592 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
6593 InsertConfigString(pLunL1Cfg, "Location", pszPath);
6594 }
6595 }
6596 catch (ConfigError &x)
6597 {
6598 /* InsertConfig threw something */
6599 return x.m_vrc;
6600 }
6601
6602 return VINF_SUCCESS;
6603}
6604
Note: See TracBrowser for help on using the repository browser.

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