VirtualBox

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

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

CloudNet: ​bugref:9469 Replace local gateway with DrvCloudTunnel. Build 25519 encryption support in libssh. Add missing version bump in machine settings to 1.18 if cloud attachment is used.

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

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