VirtualBox

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

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

Build fixes for r149382.

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

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