VirtualBox

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

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

Work around inability of XPCOM to handle enums starting with a digit.

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

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