VirtualBox

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

Last change on this file since 94321 was 94321, checked in by vboxsync, 2 years ago

Main/UsbCardReader: Drop passing pointers through CFGM in favor of using VMM2USERMETHODS::pfnQueryGenericObject, bugref:10053

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 285.8 KB
Line 
1/* $Id: ConsoleImpl2.cpp 94321 2022-03-22 11:27:12Z vboxsync $ */
2/** @file
3 * VBox Console COM Class implementation - VM Configuration Bits.
4 *
5 * @remark We've split out the code that the 64-bit VC++ v8 compiler finds
6 * problematic to optimize so we can disable optimizations and later,
7 * perhaps, find a real solution for it (like rewriting the code and
8 * to stop resemble a tonne of spaghetti).
9 */
10
11/*
12 * Copyright (C) 2006-2022 Oracle Corporation
13 *
14 * This file is part of VirtualBox Open Source Edition (OSE), as
15 * available from http://www.virtualbox.org. This file is free software;
16 * you can redistribute it and/or modify it under the terms of the GNU
17 * General Public License (GPL) as published by the Free Software
18 * Foundation, in version 2 as it comes in the "COPYING" file of the
19 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
20 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
21 */
22
23
24/*********************************************************************************************************************************
25* Header Files *
26*********************************************************************************************************************************/
27#define LOG_GROUP LOG_GROUP_MAIN_CONSOLE
28#include "LoggingNew.h"
29
30// VBoxNetCfg-win.h needs winsock2.h and thus MUST be included before any other
31// header file includes Windows.h.
32#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
33# include <VBox/VBoxNetCfg-win.h>
34#endif
35
36#include "ConsoleImpl.h"
37#include "DisplayImpl.h"
38#include "NvramStoreImpl.h"
39#ifdef VBOX_WITH_DRAG_AND_DROP
40# include "GuestImpl.h"
41# include "GuestDnDPrivate.h"
42#endif
43#include "VMMDev.h"
44#include "Global.h"
45#ifdef VBOX_WITH_PCI_PASSTHROUGH
46# include "PCIRawDevImpl.h"
47#endif
48
49// generated header
50#include "SchemaDefs.h"
51
52#include "AutoCaller.h"
53
54#include <iprt/base64.h>
55#include <iprt/buildconfig.h>
56#include <iprt/ctype.h>
57#include <iprt/dir.h>
58#include <iprt/file.h>
59#include <iprt/param.h>
60#include <iprt/path.h>
61#include <iprt/string.h>
62#include <iprt/system.h>
63#include <iprt/cpp/exception.h>
64#if 0 /* enable to play with lots of memory. */
65# include <iprt/env.h>
66#endif
67#include <iprt/stream.h>
68
69#include <VBox/vmm/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 * @returns Index into maLedSets.
648 * @param cLeds The number of LEDs in the set.
649 * @param enmType The device type.
650 * @param ppaSubTypes When not NULL, subtypes for each LED and return the
651 * array pointer here.
652 */
653uint32_t Console::i_allocateDriverLeds(uint32_t cLeds, DeviceType_T enmType, DeviceType_T **ppaSubTypes)
654{
655 Assert(cLeds > 0);
656 Assert(cLeds < 1024); /* Adjust if any driver supports >=1024 units! */
657
658 /* Grab a LED set entry before we start allocating anything so the destructor can do the cleanups. */
659 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); /* Caller should have this already. Need protect mcLedSets check and update. */
660 AssertStmt(mcLedSets < RT_ELEMENTS(maLedSets),
661 throw ConfigError("AllocateDriverPapLeds", VERR_OUT_OF_RANGE, "Too many LED sets"));
662 uint32_t const idxLedSet = mcLedSets++;
663 PLEDSET pLS = &maLedSets[idxLedSet];
664 pLS->papLeds = (PPDMLED *)RTMemAllocZ(sizeof(PPDMLED) * cLeds);
665 AssertStmt(pLS->papLeds, throw E_OUTOFMEMORY);
666 pLS->cLeds = cLeds;
667 pLS->enmType = enmType;
668 pLS->paSubTypes = NULL;
669
670 if (ppaSubTypes)
671 {
672 *ppaSubTypes = pLS->paSubTypes = (DeviceType_T *)RTMemAlloc(sizeof(DeviceType_T) * cLeds);
673 AssertStmt(pLS->paSubTypes, throw E_OUTOFMEMORY);
674 for (size_t idxSub = 0; idxSub < cLeds; ++idxSub)
675 pLS->paSubTypes[idxSub] = DeviceType_Null;
676 }
677
678 LogRel2(("mcLedSets = %d, RT_ELEMENTS(maLedSets) = %d\n", mcLedSets, RT_ELEMENTS(maLedSets)));
679 return idxLedSet;
680}
681
682
683/** @todo r=bird: Drop uFirst as it's always zero? Then s/uLast/cLeds/g. */
684void Console::i_attachStatusDriver(PCFGMNODE pCtlInst, DeviceType_T enmType,
685 uint32_t uFirst, uint32_t uLast,
686 DeviceType_T **ppaSubTypes,
687 Console::MediumAttachmentMap *pmapMediumAttachments,
688 const char *pcszDevice, unsigned uInstance)
689{
690 Assert(uFirst <= uLast);
691 PCFGMNODE pLunL0;
692 InsertConfigNode(pCtlInst, "LUN#999", &pLunL0);
693 InsertConfigString(pLunL0, "Driver", "MainStatus");
694 PCFGMNODE pCfg;
695 InsertConfigNode(pLunL0, "Config", &pCfg);
696 uint32_t const iLedSet = i_allocateDriverLeds(uLast - uFirst + 1, enmType, ppaSubTypes);
697 InsertConfigInteger(pCfg, "iLedSet", iLedSet);
698
699 InsertConfigInteger(pCfg, "HasMediumAttachments", pmapMediumAttachments != NULL);
700 if (pmapMediumAttachments)
701 {
702 AssertPtr(pcszDevice);
703 Utf8StrFmt deviceInstance("%s/%u", pcszDevice, uInstance);
704 InsertConfigString(pCfg, "DeviceInstance", deviceInstance.c_str());
705 }
706 InsertConfigInteger(pCfg, "First", uFirst);
707 InsertConfigInteger(pCfg, "Last", uLast);
708}
709
710
711/**
712 * Construct the VM configuration tree (CFGM).
713 *
714 * This is a callback for VMR3Create() call. It is called from CFGMR3Init() in
715 * the emulation thread (EMT). Any per thread COM/XPCOM initialization is done
716 * here.
717 *
718 * @returns VBox status code.
719 * @param pUVM The user mode VM handle.
720 * @param pVM The cross context VM handle.
721 * @param pVMM The VMM ring-3 vtable.
722 * @param pvConsole Pointer to the VMPowerUpTask object.
723 *
724 * @note Locks the Console object for writing.
725 */
726/*static*/ DECLCALLBACK(int)
727Console::i_configConstructor(PUVM pUVM, PVM pVM, PCVMMR3VTABLE pVMM, void *pvConsole)
728{
729 LogFlowFuncEnter();
730
731 AssertReturn(pvConsole, VERR_INVALID_POINTER);
732 ComObjPtr<Console> pConsole = static_cast<Console *>(pvConsole);
733
734 AutoCaller autoCaller(pConsole);
735 AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED);
736
737 /* lock the console because we widely use internal fields and methods */
738 AutoWriteLock alock(pConsole COMMA_LOCKVAL_SRC_POS);
739
740 /*
741 * Set the VM handle and do the rest of the job in an worker method so we
742 * can easily reset the VM handle on failure.
743 */
744 pConsole->mpUVM = pUVM;
745 pVMM->pfnVMR3RetainUVM(pUVM);
746 int vrc;
747 try
748 {
749 vrc = pConsole->i_configConstructorInner(pUVM, pVM, pVMM, &alock);
750 }
751 catch (...)
752 {
753 vrc = VERR_UNEXPECTED_EXCEPTION;
754 }
755 if (RT_FAILURE(vrc))
756 {
757 pConsole->mpUVM = NULL;
758 pVMM->pfnVMR3ReleaseUVM(pUVM);
759 }
760
761 return vrc;
762}
763
764
765/**
766 * Worker for configConstructor.
767 *
768 * @return VBox status code.
769 * @param pUVM The user mode VM handle.
770 * @param pVM The cross context VM handle.
771 * @param pVMM The VMM vtable.
772 * @param pAlock The automatic lock instance. This is for when we have
773 * to leave it in order to avoid deadlocks (ext packs and
774 * more).
775 */
776int Console::i_configConstructorInner(PUVM pUVM, PVM pVM, PCVMMR3VTABLE pVMM, AutoWriteLock *pAlock)
777{
778 RT_NOREF(pVM /* when everything is disabled */);
779 VMMDev *pVMMDev = m_pVMMDev; Assert(pVMMDev);
780 ComPtr<IMachine> pMachine = i_machine();
781
782 int rc;
783 HRESULT hrc;
784 Utf8Str strTmp;
785 Bstr bstr;
786
787#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
788
789 /*
790 * Get necessary objects and frequently used parameters.
791 */
792 ComPtr<IVirtualBox> virtualBox;
793 hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam()); H();
794
795 ComPtr<IHost> host;
796 hrc = virtualBox->COMGETTER(Host)(host.asOutParam()); H();
797
798 ComPtr<ISystemProperties> systemProperties;
799 hrc = virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam()); H();
800
801 ComPtr<IBIOSSettings> biosSettings;
802 hrc = pMachine->COMGETTER(BIOSSettings)(biosSettings.asOutParam()); H();
803
804 ComPtr<INvramStore> nvramStore;
805 hrc = pMachine->COMGETTER(NonVolatileStore)(nvramStore.asOutParam()); H();
806
807 hrc = pMachine->COMGETTER(HardwareUUID)(bstr.asOutParam()); H();
808 RTUUID HardwareUuid;
809 rc = RTUuidFromUtf16(&HardwareUuid, bstr.raw());
810 AssertRCReturn(rc, rc);
811
812 ULONG cRamMBs;
813 hrc = pMachine->COMGETTER(MemorySize)(&cRamMBs); H();
814#if 0 /* enable to play with lots of memory. */
815 if (RTEnvExist("VBOX_RAM_SIZE"))
816 cRamMBs = RTStrToUInt64(RTEnvGet("VBOX_RAM_SIZE"));
817#endif
818 uint64_t const cbRam = cRamMBs * (uint64_t)_1M;
819 uint32_t cbRamHole = MM_RAM_HOLE_SIZE_DEFAULT;
820 uint64_t uMcfgBase = 0;
821 uint32_t cbMcfgLength = 0;
822
823 ParavirtProvider_T enmParavirtProvider;
824 hrc = pMachine->GetEffectiveParavirtProvider(&enmParavirtProvider); H();
825
826 Bstr strParavirtDebug;
827 hrc = pMachine->COMGETTER(ParavirtDebug)(strParavirtDebug.asOutParam()); H();
828
829 BOOL fIOAPIC;
830 uint32_t uIoApicPciAddress = NIL_PCIBDF;
831 hrc = biosSettings->COMGETTER(IOAPICEnabled)(&fIOAPIC); H();
832
833 ChipsetType_T chipsetType;
834 hrc = pMachine->COMGETTER(ChipsetType)(&chipsetType); H();
835 if (chipsetType == ChipsetType_ICH9)
836 {
837 /* We'd better have 0x10000000 region, to cover 256 buses but this put
838 * too much load on hypervisor heap. Linux 4.8 currently complains with
839 * ``acpi PNP0A03:00: [Firmware Info]: MMCONFIG for domain 0000 [bus 00-3f]
840 * only partially covers this bridge'' */
841 cbMcfgLength = 0x4000000; //0x10000000;
842 cbRamHole += cbMcfgLength;
843 uMcfgBase = _4G - cbRamHole;
844 }
845
846 /* Get the CPU profile name. */
847 Bstr bstrCpuProfile;
848 hrc = pMachine->COMGETTER(CPUProfile)(bstrCpuProfile.asOutParam()); H();
849
850 /*
851 * Figure out the IOMMU config.
852 */
853#if defined(VBOX_WITH_IOMMU_AMD) || defined(VBOX_WITH_IOMMU_INTEL)
854 IommuType_T enmIommuType;
855 hrc = pMachine->COMGETTER(IommuType)(&enmIommuType); H();
856
857 /* Resolve 'automatic' type to an Intel or AMD IOMMU based on the host CPU. */
858 if (enmIommuType == IommuType_Automatic)
859 {
860 if ( bstrCpuProfile.startsWith("AMD")
861 || bstrCpuProfile.startsWith("Quad-Core AMD")
862 || bstrCpuProfile.startsWith("Hygon"))
863 enmIommuType = IommuType_AMD;
864 else if (bstrCpuProfile.startsWith("Intel"))
865 {
866 if ( bstrCpuProfile.equals("Intel 8086")
867 || bstrCpuProfile.equals("Intel 80186")
868 || bstrCpuProfile.equals("Intel 80286")
869 || bstrCpuProfile.equals("Intel 80386")
870 || bstrCpuProfile.equals("Intel 80486"))
871 enmIommuType = IommuType_None;
872 else
873 enmIommuType = IommuType_Intel;
874 }
875# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
876 else if (ASMIsAmdCpu())
877 enmIommuType = IommuType_AMD;
878 else if (ASMIsIntelCpu())
879 enmIommuType = IommuType_Intel;
880# endif
881 else
882 {
883 /** @todo Should we handle other CPUs like Shanghai, VIA etc. here? */
884 LogRel(("WARNING! Unrecognized CPU type, IOMMU disabled.\n"));
885 enmIommuType = IommuType_None;
886 }
887 }
888
889 if (enmIommuType == IommuType_AMD)
890 {
891# ifdef VBOX_WITH_IOMMU_AMD
892 /*
893 * Reserve the specific PCI address of the "SB I/O APIC" when using
894 * an AMD IOMMU. Required by Linux guests, see @bugref{9654#c23}.
895 */
896 uIoApicPciAddress = VBOX_PCI_BDF_SB_IOAPIC;
897# else
898 LogRel(("WARNING! AMD IOMMU not supported, IOMMU disabled.\n"));
899 enmIommuType = IommuType_None;
900# endif
901 }
902
903 if (enmIommuType == IommuType_Intel)
904 {
905# ifdef VBOX_WITH_IOMMU_INTEL
906 /*
907 * Reserve a unique PCI address for the I/O APIC when using
908 * an Intel IOMMU. For convenience we use the same address as
909 * we do on AMD, see @bugref{9967#c13}.
910 */
911 uIoApicPciAddress = VBOX_PCI_BDF_SB_IOAPIC;
912# else
913 LogRel(("WARNING! Intel IOMMU not supported, IOMMU disabled.\n"));
914 enmIommuType = IommuType_None;
915# endif
916 }
917
918 if ( enmIommuType == IommuType_AMD
919 || enmIommuType == IommuType_Intel)
920 {
921 if (chipsetType != ChipsetType_ICH9)
922 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
923 N_("IOMMU uses MSIs which requires the ICH9 chipset implementation."));
924 if (!fIOAPIC)
925 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
926 N_("IOMMU requires an I/O APIC for remapping interrupts."));
927 }
928#else
929 IommuType_T const enmIommuType = IommuType_None;
930#endif
931
932 /* Instantiate the bus assignment manager. */
933 Assert(enmIommuType != IommuType_Automatic);
934 BusAssignmentManager *pBusMgr = mBusMgr = BusAssignmentManager::createInstance(pVMM, chipsetType, enmIommuType);
935
936 ULONG cCpus = 1;
937 hrc = pMachine->COMGETTER(CPUCount)(&cCpus); H();
938
939 ULONG ulCpuExecutionCap = 100;
940 hrc = pMachine->COMGETTER(CPUExecutionCap)(&ulCpuExecutionCap); H();
941
942 Bstr osTypeId;
943 hrc = pMachine->COMGETTER(OSTypeId)(osTypeId.asOutParam()); H();
944 LogRel(("Guest OS type: '%s'\n", Utf8Str(osTypeId).c_str()));
945
946 APICMode_T apicMode;
947 hrc = biosSettings->COMGETTER(APICMode)(&apicMode); H();
948 uint32_t uFwAPIC;
949 switch (apicMode)
950 {
951 case APICMode_Disabled:
952 uFwAPIC = 0;
953 break;
954 case APICMode_APIC:
955 uFwAPIC = 1;
956 break;
957 case APICMode_X2APIC:
958 uFwAPIC = 2;
959 break;
960 default:
961 AssertMsgFailed(("Invalid APICMode=%d\n", apicMode));
962 uFwAPIC = 1;
963 break;
964 }
965
966 ComPtr<IGuestOSType> pGuestOSType;
967 virtualBox->GetGuestOSType(osTypeId.raw(), pGuestOSType.asOutParam());
968
969 BOOL fOsXGuest = FALSE;
970 BOOL fWinGuest = FALSE;
971 if (!pGuestOSType.isNull())
972 {
973 Bstr guestTypeFamilyId;
974 hrc = pGuestOSType->COMGETTER(FamilyId)(guestTypeFamilyId.asOutParam()); H();
975 fOsXGuest = guestTypeFamilyId == Bstr("MacOS");
976 fWinGuest = guestTypeFamilyId == Bstr("Windows");
977 }
978
979 ULONG maxNetworkAdapters;
980 hrc = systemProperties->GetMaxNetworkAdapters(chipsetType, &maxNetworkAdapters); H();
981
982 /*
983 * Get root node first.
984 * This is the only node in the tree.
985 */
986 PCFGMNODE pRoot = pVMM->pfnCFGMR3GetRootU(pUVM);
987 Assert(pRoot);
988
989 // InsertConfigString throws
990 try
991 {
992
993 /*
994 * Set the root (and VMM) level values.
995 */
996 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
997 InsertConfigString(pRoot, "Name", bstr);
998 InsertConfigBytes(pRoot, "UUID", &HardwareUuid, sizeof(HardwareUuid));
999 InsertConfigInteger(pRoot, "RamSize", cbRam);
1000 InsertConfigInteger(pRoot, "RamHoleSize", cbRamHole);
1001 InsertConfigInteger(pRoot, "NumCPUs", cCpus);
1002 InsertConfigInteger(pRoot, "CpuExecutionCap", ulCpuExecutionCap);
1003 InsertConfigInteger(pRoot, "TimerMillies", 10);
1004
1005 BOOL fPageFusion = FALSE;
1006 hrc = pMachine->COMGETTER(PageFusionEnabled)(&fPageFusion); H();
1007 InsertConfigInteger(pRoot, "PageFusionAllowed", fPageFusion); /* boolean */
1008
1009 /* Not necessary, but makes sure this setting ends up in the release log. */
1010 ULONG ulBalloonSize = 0;
1011 hrc = pMachine->COMGETTER(MemoryBalloonSize)(&ulBalloonSize); H();
1012 InsertConfigInteger(pRoot, "MemBalloonSize", ulBalloonSize);
1013
1014 /*
1015 * EM values (before CPUM as it may need to set IemExecutesAll).
1016 */
1017 PCFGMNODE pEM;
1018 InsertConfigNode(pRoot, "EM", &pEM);
1019
1020 /* Triple fault behavior. */
1021 BOOL fTripleFaultReset = false;
1022 hrc = pMachine->GetCPUProperty(CPUPropertyType_TripleFaultReset, &fTripleFaultReset); H();
1023 InsertConfigInteger(pEM, "TripleFaultReset", fTripleFaultReset);
1024
1025 /*
1026 * CPUM values.
1027 */
1028 PCFGMNODE pCPUM;
1029 InsertConfigNode(pRoot, "CPUM", &pCPUM);
1030 PCFGMNODE pIsaExts;
1031 InsertConfigNode(pCPUM, "IsaExts", &pIsaExts);
1032
1033 /* Host CPUID leaf overrides. */
1034 for (uint32_t iOrdinal = 0; iOrdinal < _4K; iOrdinal++)
1035 {
1036 ULONG uLeaf, uSubLeaf, uEax, uEbx, uEcx, uEdx;
1037 hrc = pMachine->GetCPUIDLeafByOrdinal(iOrdinal, &uLeaf, &uSubLeaf, &uEax, &uEbx, &uEcx, &uEdx);
1038 if (hrc == E_INVALIDARG)
1039 break;
1040 H();
1041 PCFGMNODE pLeaf;
1042 InsertConfigNode(pCPUM, Utf8StrFmt("HostCPUID/%RX32", uLeaf).c_str(), &pLeaf);
1043 /** @todo Figure out how to tell the VMM about uSubLeaf */
1044 InsertConfigInteger(pLeaf, "eax", uEax);
1045 InsertConfigInteger(pLeaf, "ebx", uEbx);
1046 InsertConfigInteger(pLeaf, "ecx", uEcx);
1047 InsertConfigInteger(pLeaf, "edx", uEdx);
1048 }
1049
1050 /* We must limit CPUID count for Windows NT 4, as otherwise it stops
1051 with error 0x3e (MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED). */
1052 if (osTypeId == "WindowsNT4")
1053 {
1054 LogRel(("Limiting CPUID leaf count for NT4 guests\n"));
1055 InsertConfigInteger(pCPUM, "NT4LeafLimit", true);
1056 }
1057
1058 if (fOsXGuest)
1059 {
1060 /* Expose extended MWAIT features to Mac OS X guests. */
1061 LogRel(("Using MWAIT extensions\n"));
1062 InsertConfigInteger(pIsaExts, "MWaitExtensions", true);
1063
1064 /* Fake the CPU family/model so the guest works. This is partly
1065 because older mac releases really doesn't work on newer cpus,
1066 and partly because mac os x expects more from systems with newer
1067 cpus (MSRs, power features, whatever). */
1068 uint32_t uMaxIntelFamilyModelStep = UINT32_MAX;
1069 if ( osTypeId == "MacOS"
1070 || osTypeId == "MacOS_64")
1071 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482. */
1072 else if ( osTypeId == "MacOS106"
1073 || osTypeId == "MacOS106_64")
1074 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */
1075 else if ( osTypeId == "MacOS107"
1076 || osTypeId == "MacOS107_64")
1077 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */ /** @todo figure out
1078 what is required here. */
1079 else if ( osTypeId == "MacOS108"
1080 || osTypeId == "MacOS108_64")
1081 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */ /** @todo figure out
1082 what is required here. */
1083 else if ( osTypeId == "MacOS109"
1084 || osTypeId == "MacOS109_64")
1085 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */ /** @todo figure
1086 out what is required here. */
1087 if (uMaxIntelFamilyModelStep != UINT32_MAX)
1088 InsertConfigInteger(pCPUM, "MaxIntelFamilyModelStep", uMaxIntelFamilyModelStep);
1089 }
1090
1091 /* CPU Portability level, */
1092 ULONG uCpuIdPortabilityLevel = 0;
1093 hrc = pMachine->COMGETTER(CPUIDPortabilityLevel)(&uCpuIdPortabilityLevel); H();
1094 InsertConfigInteger(pCPUM, "PortableCpuIdLevel", uCpuIdPortabilityLevel);
1095
1096 /* Physical Address Extension (PAE) */
1097 BOOL fEnablePAE = false;
1098 hrc = pMachine->GetCPUProperty(CPUPropertyType_PAE, &fEnablePAE); H();
1099 InsertConfigInteger(pRoot, "EnablePAE", fEnablePAE);
1100
1101 /* APIC/X2APIC configuration */
1102 BOOL fEnableAPIC = true;
1103 BOOL fEnableX2APIC = true;
1104 hrc = pMachine->GetCPUProperty(CPUPropertyType_APIC, &fEnableAPIC); H();
1105 hrc = pMachine->GetCPUProperty(CPUPropertyType_X2APIC, &fEnableX2APIC); H();
1106 if (fEnableX2APIC)
1107 Assert(fEnableAPIC);
1108
1109 /* CPUM profile name. */
1110 InsertConfigString(pCPUM, "GuestCpuName", bstrCpuProfile);
1111
1112 /*
1113 * Temporary(?) hack to make sure we emulate the ancient 16-bit CPUs
1114 * correctly. There are way too many #UDs we'll miss using VT-x,
1115 * raw-mode or qemu for the 186 and 286, while we'll get undefined opcodes
1116 * dead wrong on 8086 (see http://www.os2museum.com/wp/undocumented-8086-opcodes/).
1117 */
1118 if ( bstrCpuProfile.equals("Intel 80386") /* just for now */
1119 || bstrCpuProfile.equals("Intel 80286")
1120 || bstrCpuProfile.equals("Intel 80186")
1121 || bstrCpuProfile.equals("Nec V20")
1122 || bstrCpuProfile.equals("Intel 8086") )
1123 {
1124 InsertConfigInteger(pEM, "IemExecutesAll", true);
1125 if (!bstrCpuProfile.equals("Intel 80386"))
1126 {
1127 fEnableAPIC = false;
1128 fIOAPIC = false;
1129 }
1130 fEnableX2APIC = false;
1131 }
1132
1133 /* Adjust firmware APIC handling to stay within the VCPU limits. */
1134 if (uFwAPIC == 2 && !fEnableX2APIC)
1135 {
1136 if (fEnableAPIC)
1137 uFwAPIC = 1;
1138 else
1139 uFwAPIC = 0;
1140 LogRel(("Limiting the firmware APIC level from x2APIC to %s\n", fEnableAPIC ? "APIC" : "Disabled"));
1141 }
1142 else if (uFwAPIC == 1 && !fEnableAPIC)
1143 {
1144 uFwAPIC = 0;
1145 LogRel(("Limiting the firmware APIC level from APIC to Disabled\n"));
1146 }
1147
1148 /* Speculation Control. */
1149 BOOL fSpecCtrl = FALSE;
1150 hrc = pMachine->GetCPUProperty(CPUPropertyType_SpecCtrl, &fSpecCtrl); H();
1151 InsertConfigInteger(pCPUM, "SpecCtrl", fSpecCtrl);
1152
1153 /* Nested VT-x / AMD-V. */
1154 BOOL fNestedHWVirt = FALSE;
1155 hrc = pMachine->GetCPUProperty(CPUPropertyType_HWVirt, &fNestedHWVirt); H();
1156 InsertConfigInteger(pCPUM, "NestedHWVirt", fNestedHWVirt ? true : false);
1157
1158 /*
1159 * Hardware virtualization extensions.
1160 */
1161 BOOL fSupportsHwVirtEx;
1162 hrc = host->GetProcessorFeature(ProcessorFeature_HWVirtEx, &fSupportsHwVirtEx); H();
1163
1164 BOOL fIsGuest64Bit;
1165 hrc = pMachine->GetCPUProperty(CPUPropertyType_LongMode, &fIsGuest64Bit); H();
1166 if (fIsGuest64Bit)
1167 {
1168 BOOL fSupportsLongMode;
1169 hrc = host->GetProcessorFeature(ProcessorFeature_LongMode, &fSupportsLongMode); H();
1170 if (!fSupportsLongMode)
1171 {
1172 LogRel(("WARNING! 64-bit guest type selected but the host CPU does NOT support 64-bit.\n"));
1173 fIsGuest64Bit = FALSE;
1174 }
1175 if (!fSupportsHwVirtEx)
1176 {
1177 LogRel(("WARNING! 64-bit guest type selected but the host CPU does NOT support HW virtualization.\n"));
1178 fIsGuest64Bit = FALSE;
1179 }
1180 }
1181
1182 /* Sanitize valid/useful APIC combinations, see @bugref{8868}. */
1183 if (!fEnableAPIC)
1184 {
1185 if (fIsGuest64Bit)
1186 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1187 N_("Cannot disable the APIC for a 64-bit guest."));
1188 if (cCpus > 1)
1189 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1190 N_("Cannot disable the APIC for an SMP guest."));
1191 if (fIOAPIC)
1192 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1193 N_("Cannot disable the APIC when the I/O APIC is present."));
1194 }
1195
1196 BOOL fHMEnabled;
1197 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_Enabled, &fHMEnabled); H();
1198 if (cCpus > 1 && !fHMEnabled)
1199 {
1200 LogRel(("Forced fHMEnabled to TRUE by SMP guest.\n"));
1201 fHMEnabled = TRUE;
1202 }
1203
1204 BOOL fHMForced;
1205 fHMEnabled = fHMForced = TRUE;
1206 LogRel(("fHMForced=true - No raw-mode support in this build!\n"));
1207 if (!fHMForced) /* No need to query if already forced above. */
1208 {
1209 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_Force, &fHMForced); H();
1210 if (fHMForced)
1211 LogRel(("fHMForced=true - HWVirtExPropertyType_Force\n"));
1212 }
1213 InsertConfigInteger(pRoot, "HMEnabled", fHMEnabled);
1214
1215 /* /HM/xyz */
1216 PCFGMNODE pHM;
1217 InsertConfigNode(pRoot, "HM", &pHM);
1218 InsertConfigInteger(pHM, "HMForced", fHMForced);
1219 if (fHMEnabled)
1220 {
1221 /* Indicate whether 64-bit guests are supported or not. */
1222 InsertConfigInteger(pHM, "64bitEnabled", fIsGuest64Bit);
1223#if ARCH_BITS == 32 /* The recompiler must use VBoxREM64 (32-bit host only). */
1224 PCFGMNODE pREM;
1225 InsertConfigNode(pRoot, "REM", &pREM);
1226 InsertConfigInteger(pREM, "64bitEnabled", 1);
1227#endif
1228
1229 /** @todo Not exactly pretty to check strings; VBOXOSTYPE would be better,
1230 but that requires quite a bit of API change in Main. */
1231 if ( fIOAPIC
1232 && ( osTypeId == "WindowsNT4"
1233 || osTypeId == "Windows2000"
1234 || osTypeId == "WindowsXP"
1235 || osTypeId == "Windows2003"))
1236 {
1237 /* Only allow TPR patching for NT, Win2k, XP and Windows Server 2003. (32 bits mode)
1238 * We may want to consider adding more guest OSes (Solaris) later on.
1239 */
1240 InsertConfigInteger(pHM, "TPRPatchingEnabled", 1);
1241 }
1242 }
1243
1244 /* HWVirtEx exclusive mode */
1245 BOOL fHMExclusive = true;
1246 hrc = systemProperties->COMGETTER(ExclusiveHwVirt)(&fHMExclusive); H();
1247 InsertConfigInteger(pHM, "Exclusive", fHMExclusive);
1248
1249 /* Nested paging (VT-x/AMD-V) */
1250 BOOL fEnableNestedPaging = false;
1251 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_NestedPaging, &fEnableNestedPaging); H();
1252 InsertConfigInteger(pHM, "EnableNestedPaging", fEnableNestedPaging);
1253
1254 /* Large pages; requires nested paging */
1255 BOOL fEnableLargePages = false;
1256 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_LargePages, &fEnableLargePages); H();
1257 InsertConfigInteger(pHM, "EnableLargePages", fEnableLargePages);
1258
1259 /* VPID (VT-x) */
1260 BOOL fEnableVPID = false;
1261 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_VPID, &fEnableVPID); H();
1262 InsertConfigInteger(pHM, "EnableVPID", fEnableVPID);
1263
1264 /* Unrestricted execution aka UX (VT-x) */
1265 BOOL fEnableUX = false;
1266 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_UnrestrictedExecution, &fEnableUX); H();
1267 InsertConfigInteger(pHM, "EnableUX", fEnableUX);
1268
1269 /* Virtualized VMSAVE/VMLOAD (AMD-V) */
1270 BOOL fVirtVmsaveVmload = true;
1271 hrc = host->GetProcessorFeature(ProcessorFeature_VirtVmsaveVmload, &fVirtVmsaveVmload); H();
1272 InsertConfigInteger(pHM, "SvmVirtVmsaveVmload", fVirtVmsaveVmload);
1273
1274 /* Indirect branch prediction boundraries. */
1275 BOOL fIBPBOnVMExit = false;
1276 hrc = pMachine->GetCPUProperty(CPUPropertyType_IBPBOnVMExit, &fIBPBOnVMExit); H();
1277 InsertConfigInteger(pHM, "IBPBOnVMExit", fIBPBOnVMExit);
1278
1279 BOOL fIBPBOnVMEntry = false;
1280 hrc = pMachine->GetCPUProperty(CPUPropertyType_IBPBOnVMEntry, &fIBPBOnVMEntry); H();
1281 InsertConfigInteger(pHM, "IBPBOnVMEntry", fIBPBOnVMEntry);
1282
1283 BOOL fSpecCtrlByHost = false;
1284 hrc = pMachine->GetCPUProperty(CPUPropertyType_SpecCtrlByHost, &fSpecCtrlByHost); H();
1285 InsertConfigInteger(pHM, "SpecCtrlByHost", fSpecCtrlByHost);
1286
1287 BOOL fL1DFlushOnSched = true;
1288 hrc = pMachine->GetCPUProperty(CPUPropertyType_L1DFlushOnEMTScheduling, &fL1DFlushOnSched); H();
1289 InsertConfigInteger(pHM, "L1DFlushOnSched", fL1DFlushOnSched);
1290
1291 BOOL fL1DFlushOnVMEntry = false;
1292 hrc = pMachine->GetCPUProperty(CPUPropertyType_L1DFlushOnVMEntry, &fL1DFlushOnVMEntry); H();
1293 InsertConfigInteger(pHM, "L1DFlushOnVMEntry", fL1DFlushOnVMEntry);
1294
1295 BOOL fMDSClearOnSched = true;
1296 hrc = pMachine->GetCPUProperty(CPUPropertyType_MDSClearOnEMTScheduling, &fMDSClearOnSched); H();
1297 InsertConfigInteger(pHM, "MDSClearOnSched", fMDSClearOnSched);
1298
1299 BOOL fMDSClearOnVMEntry = false;
1300 hrc = pMachine->GetCPUProperty(CPUPropertyType_MDSClearOnVMEntry, &fMDSClearOnVMEntry); H();
1301 InsertConfigInteger(pHM, "MDSClearOnVMEntry", fMDSClearOnVMEntry);
1302
1303 /* Reset overwrite. */
1304 mfTurnResetIntoPowerOff = GetExtraDataBoth(virtualBox, pMachine,
1305 "VBoxInternal2/TurnResetIntoPowerOff", &strTmp)->equals("1");
1306 if (mfTurnResetIntoPowerOff)
1307 InsertConfigInteger(pRoot, "PowerOffInsteadOfReset", 1);
1308
1309 /* Use NEM rather than HM. */
1310 BOOL fUseNativeApi = false;
1311 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_UseNativeApi, &fUseNativeApi); H();
1312 InsertConfigInteger(pHM, "UseNEMInstead", fUseNativeApi);
1313
1314 /* Enable workaround for missing TLB flush for OS/2 guests, see ticketref:20625. */
1315 if (osTypeId.startsWith("OS2"))
1316 InsertConfigInteger(pHM, "MissingOS2TlbFlushWorkaround", 1);
1317
1318 /*
1319 * NEM
1320 */
1321 PCFGMNODE pNEM;
1322 InsertConfigNode(pRoot, "NEM", &pNEM);
1323 InsertConfigInteger(pNEM, "Allow64BitGuests", fIsGuest64Bit);
1324
1325 /*
1326 * Paravirt. provider.
1327 */
1328 PCFGMNODE pParavirtNode;
1329 InsertConfigNode(pRoot, "GIM", &pParavirtNode);
1330 const char *pcszParavirtProvider;
1331 bool fGimDeviceNeeded = true;
1332 switch (enmParavirtProvider)
1333 {
1334 case ParavirtProvider_None:
1335 pcszParavirtProvider = "None";
1336 fGimDeviceNeeded = false;
1337 break;
1338
1339 case ParavirtProvider_Minimal:
1340 pcszParavirtProvider = "Minimal";
1341 break;
1342
1343 case ParavirtProvider_HyperV:
1344 pcszParavirtProvider = "HyperV";
1345 break;
1346
1347 case ParavirtProvider_KVM:
1348 pcszParavirtProvider = "KVM";
1349 break;
1350
1351 default:
1352 AssertMsgFailed(("Invalid enmParavirtProvider=%d\n", enmParavirtProvider));
1353 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("Invalid paravirt. provider '%d'"),
1354 enmParavirtProvider);
1355 }
1356 InsertConfigString(pParavirtNode, "Provider", pcszParavirtProvider);
1357
1358 /*
1359 * Parse paravirt. debug options.
1360 */
1361 bool fGimDebug = false;
1362 com::Utf8Str strGimDebugAddress = "127.0.0.1";
1363 uint32_t uGimDebugPort = 50000;
1364 if (strParavirtDebug.isNotEmpty())
1365 {
1366 /* Hyper-V debug options. */
1367 if (enmParavirtProvider == ParavirtProvider_HyperV)
1368 {
1369 bool fGimHvDebug = false;
1370 com::Utf8Str strGimHvVendor;
1371 bool fGimHvVsIf = false;
1372 bool fGimHvHypercallIf = false;
1373
1374 size_t uPos = 0;
1375 com::Utf8Str strDebugOptions = strParavirtDebug;
1376 com::Utf8Str strKey;
1377 com::Utf8Str strVal;
1378 while ((uPos = strDebugOptions.parseKeyValue(strKey, strVal, uPos)) != com::Utf8Str::npos)
1379 {
1380 if (strKey == "enabled")
1381 {
1382 if (strVal.toUInt32() == 1)
1383 {
1384 /* Apply defaults.
1385 The defaults are documented in the user manual,
1386 changes need to be reflected accordingly. */
1387 fGimHvDebug = true;
1388 strGimHvVendor = "Microsoft Hv";
1389 fGimHvVsIf = true;
1390 fGimHvHypercallIf = false;
1391 }
1392 /* else: ignore, i.e. don't assert below with 'enabled=0'. */
1393 }
1394 else if (strKey == "address")
1395 strGimDebugAddress = strVal;
1396 else if (strKey == "port")
1397 uGimDebugPort = strVal.toUInt32();
1398 else if (strKey == "vendor")
1399 strGimHvVendor = strVal;
1400 else if (strKey == "vsinterface")
1401 fGimHvVsIf = RT_BOOL(strVal.toUInt32());
1402 else if (strKey == "hypercallinterface")
1403 fGimHvHypercallIf = RT_BOOL(strVal.toUInt32());
1404 else
1405 {
1406 AssertMsgFailed(("Unrecognized Hyper-V debug option '%s'\n", strKey.c_str()));
1407 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1408 N_("Unrecognized Hyper-V debug option '%s' in '%s'"), strKey.c_str(),
1409 strDebugOptions.c_str());
1410 }
1411 }
1412
1413 /* Update HyperV CFGM node with active debug options. */
1414 if (fGimHvDebug)
1415 {
1416 PCFGMNODE pHvNode;
1417 InsertConfigNode(pParavirtNode, "HyperV", &pHvNode);
1418 InsertConfigString(pHvNode, "VendorID", strGimHvVendor);
1419 InsertConfigInteger(pHvNode, "VSInterface", fGimHvVsIf ? 1 : 0);
1420 InsertConfigInteger(pHvNode, "HypercallDebugInterface", fGimHvHypercallIf ? 1 : 0);
1421 fGimDebug = true;
1422 }
1423 }
1424 }
1425
1426 /*
1427 * MM values.
1428 */
1429 PCFGMNODE pMM;
1430 InsertConfigNode(pRoot, "MM", &pMM);
1431 InsertConfigInteger(pMM, "CanUseLargerHeap", chipsetType == ChipsetType_ICH9);
1432
1433 /*
1434 * PDM config.
1435 * Load drivers in VBoxC.[so|dll]
1436 */
1437 PCFGMNODE pPDM;
1438 PCFGMNODE pNode;
1439 PCFGMNODE pMod;
1440 InsertConfigNode(pRoot, "PDM", &pPDM);
1441 InsertConfigNode(pPDM, "Devices", &pNode);
1442 InsertConfigNode(pPDM, "Drivers", &pNode);
1443 InsertConfigNode(pNode, "VBoxC", &pMod);
1444#ifdef VBOX_WITH_XPCOM
1445 // VBoxC is located in the components subdirectory
1446 char szPathVBoxC[RTPATH_MAX];
1447 rc = RTPathAppPrivateArch(szPathVBoxC, RTPATH_MAX - sizeof("/components/VBoxC")); AssertRC(rc);
1448 strcat(szPathVBoxC, "/components/VBoxC");
1449 InsertConfigString(pMod, "Path", szPathVBoxC);
1450#else
1451 InsertConfigString(pMod, "Path", "VBoxC");
1452#endif
1453
1454
1455 /*
1456 * Block cache settings.
1457 */
1458 PCFGMNODE pPDMBlkCache;
1459 InsertConfigNode(pPDM, "BlkCache", &pPDMBlkCache);
1460
1461 /* I/O cache size */
1462 ULONG ioCacheSize = 5;
1463 hrc = pMachine->COMGETTER(IOCacheSize)(&ioCacheSize); H();
1464 InsertConfigInteger(pPDMBlkCache, "CacheSize", ioCacheSize * _1M);
1465
1466 /*
1467 * Bandwidth groups.
1468 */
1469 ComPtr<IBandwidthControl> bwCtrl;
1470
1471 hrc = pMachine->COMGETTER(BandwidthControl)(bwCtrl.asOutParam()); H();
1472
1473 com::SafeIfaceArray<IBandwidthGroup> bwGroups;
1474 hrc = bwCtrl->GetAllBandwidthGroups(ComSafeArrayAsOutParam(bwGroups)); H();
1475
1476 PCFGMNODE pAc;
1477 InsertConfigNode(pPDM, "AsyncCompletion", &pAc);
1478 PCFGMNODE pAcFile;
1479 InsertConfigNode(pAc, "File", &pAcFile);
1480 PCFGMNODE pAcFileBwGroups;
1481 InsertConfigNode(pAcFile, "BwGroups", &pAcFileBwGroups);
1482#ifdef VBOX_WITH_NETSHAPER
1483 PCFGMNODE pNetworkShaper;
1484 InsertConfigNode(pPDM, "NetworkShaper", &pNetworkShaper);
1485 PCFGMNODE pNetworkBwGroups;
1486 InsertConfigNode(pNetworkShaper, "BwGroups", &pNetworkBwGroups);
1487#endif /* VBOX_WITH_NETSHAPER */
1488
1489 for (size_t i = 0; i < bwGroups.size(); i++)
1490 {
1491 Bstr strName;
1492 hrc = bwGroups[i]->COMGETTER(Name)(strName.asOutParam()); H();
1493 if (strName.isEmpty())
1494 return pVMM->pfnVMR3SetError(pUVM, VERR_CFGM_NO_NODE, RT_SRC_POS, N_("No bandwidth group name specified"));
1495
1496 BandwidthGroupType_T enmType = BandwidthGroupType_Null;
1497 hrc = bwGroups[i]->COMGETTER(Type)(&enmType); H();
1498 LONG64 cMaxBytesPerSec = 0;
1499 hrc = bwGroups[i]->COMGETTER(MaxBytesPerSec)(&cMaxBytesPerSec); H();
1500
1501 if (enmType == BandwidthGroupType_Disk)
1502 {
1503 PCFGMNODE pBwGroup;
1504 InsertConfigNode(pAcFileBwGroups, Utf8Str(strName).c_str(), &pBwGroup);
1505 InsertConfigInteger(pBwGroup, "Max", cMaxBytesPerSec);
1506 InsertConfigInteger(pBwGroup, "Start", cMaxBytesPerSec);
1507 InsertConfigInteger(pBwGroup, "Step", 0);
1508 }
1509#ifdef VBOX_WITH_NETSHAPER
1510 else if (enmType == BandwidthGroupType_Network)
1511 {
1512 /* Network bandwidth groups. */
1513 PCFGMNODE pBwGroup;
1514 InsertConfigNode(pNetworkBwGroups, Utf8Str(strName).c_str(), &pBwGroup);
1515 InsertConfigInteger(pBwGroup, "Max", cMaxBytesPerSec);
1516 }
1517#endif /* VBOX_WITH_NETSHAPER */
1518 }
1519
1520 /*
1521 * Devices
1522 */
1523 PCFGMNODE pDevices = NULL; /* /Devices */
1524 PCFGMNODE pDev = NULL; /* /Devices/Dev/ */
1525 PCFGMNODE pInst = NULL; /* /Devices/Dev/0/ */
1526 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
1527 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
1528 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */
1529 PCFGMNODE pBiosCfg = NULL; /* /Devices/pcbios/0/Config/ */
1530 PCFGMNODE pNetBootCfg = NULL; /* /Devices/pcbios/0/Config/NetBoot/ */
1531
1532 InsertConfigNode(pRoot, "Devices", &pDevices);
1533
1534 /*
1535 * GIM Device
1536 */
1537 if (fGimDeviceNeeded)
1538 {
1539 InsertConfigNode(pDevices, "GIMDev", &pDev);
1540 InsertConfigNode(pDev, "0", &pInst);
1541 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1542 //InsertConfigNode(pInst, "Config", &pCfg);
1543
1544 if (fGimDebug)
1545 {
1546 InsertConfigNode(pInst, "LUN#998", &pLunL0);
1547 InsertConfigString(pLunL0, "Driver", "UDP");
1548 InsertConfigNode(pLunL0, "Config", &pLunL1);
1549 InsertConfigString(pLunL1, "ServerAddress", strGimDebugAddress);
1550 InsertConfigInteger(pLunL1, "ServerPort", uGimDebugPort);
1551 }
1552 }
1553
1554 /*
1555 * PC Arch.
1556 */
1557 InsertConfigNode(pDevices, "pcarch", &pDev);
1558 InsertConfigNode(pDev, "0", &pInst);
1559 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1560 InsertConfigNode(pInst, "Config", &pCfg);
1561
1562 /*
1563 * The time offset
1564 */
1565 LONG64 timeOffset;
1566 hrc = biosSettings->COMGETTER(TimeOffset)(&timeOffset); H();
1567 PCFGMNODE pTMNode;
1568 InsertConfigNode(pRoot, "TM", &pTMNode);
1569 InsertConfigInteger(pTMNode, "UTCOffset", timeOffset * 1000000);
1570
1571 /*
1572 * DMA
1573 */
1574 InsertConfigNode(pDevices, "8237A", &pDev);
1575 InsertConfigNode(pDev, "0", &pInst);
1576 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1577
1578 /*
1579 * PCI buses.
1580 */
1581 uint32_t uIocPCIAddress, uHbcPCIAddress;
1582 switch (chipsetType)
1583 {
1584 default:
1585 AssertFailed();
1586 RT_FALL_THRU();
1587 case ChipsetType_PIIX3:
1588 /* Create the base for adding bridges on demand */
1589 InsertConfigNode(pDevices, "pcibridge", NULL);
1590
1591 InsertConfigNode(pDevices, "pci", &pDev);
1592 uHbcPCIAddress = (0x0 << 16) | 0;
1593 uIocPCIAddress = (0x1 << 16) | 0; // ISA controller
1594 break;
1595 case ChipsetType_ICH9:
1596 /* Create the base for adding bridges on demand */
1597 InsertConfigNode(pDevices, "ich9pcibridge", NULL);
1598
1599 InsertConfigNode(pDevices, "ich9pci", &pDev);
1600 uHbcPCIAddress = (0x1e << 16) | 0;
1601 uIocPCIAddress = (0x1f << 16) | 0; // LPC controller
1602 break;
1603 }
1604 InsertConfigNode(pDev, "0", &pInst);
1605 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1606 InsertConfigNode(pInst, "Config", &pCfg);
1607 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1608 if (chipsetType == ChipsetType_ICH9)
1609 {
1610 /* Provide MCFG info */
1611 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
1612 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
1613
1614#ifdef VBOX_WITH_PCI_PASSTHROUGH
1615 /* Add PCI passthrough devices */
1616 hrc = i_attachRawPCIDevices(pUVM, pBusMgr, pDevices); H();
1617#endif
1618
1619 if (enmIommuType == IommuType_AMD)
1620 {
1621 /* AMD IOMMU. */
1622 InsertConfigNode(pDevices, "iommu-amd", &pDev);
1623 InsertConfigNode(pDev, "0", &pInst);
1624 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1625 InsertConfigNode(pInst, "Config", &pCfg);
1626 hrc = pBusMgr->assignPCIDevice("iommu-amd", pInst); H();
1627
1628 /* The AMD IOMMU device needs to know which PCI slot it's in, see @bugref{9654#c104}. */
1629 {
1630 PCIBusAddress Address;
1631 if (pBusMgr->findPCIAddress("iommu-amd", 0, Address))
1632 {
1633 uint32_t const u32IommuAddress = (Address.miDevice << 16) | Address.miFn;
1634 InsertConfigInteger(pCfg, "PCIAddress", u32IommuAddress);
1635 }
1636 else
1637 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1638 N_("Failed to find PCI address of the assigned IOMMU device!"));
1639 }
1640
1641 PCIBusAddress PCIAddr = PCIBusAddress((int32_t)uIoApicPciAddress);
1642 hrc = pBusMgr->assignPCIDevice("sb-ioapic", NULL /* pCfg */, PCIAddr, true /*fGuestAddressRequired*/); H();
1643 }
1644 else if (enmIommuType == IommuType_Intel)
1645 {
1646 /* Intel IOMMU. */
1647 InsertConfigNode(pDevices, "iommu-intel", &pDev);
1648 InsertConfigNode(pDev, "0", &pInst);
1649 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1650 InsertConfigNode(pInst, "Config", &pCfg);
1651 hrc = pBusMgr->assignPCIDevice("iommu-intel", pInst); H();
1652
1653 PCIBusAddress PCIAddr = PCIBusAddress((int32_t)uIoApicPciAddress);
1654 hrc = pBusMgr->assignPCIDevice("sb-ioapic", NULL /* pCfg */, PCIAddr, true /*fGuestAddressRequired*/); H();
1655 }
1656 }
1657
1658 /*
1659 * Enable the following devices: HPET, SMC and LPC on MacOS X guests or on ICH9 chipset
1660 */
1661
1662 /*
1663 * High Precision Event Timer (HPET)
1664 */
1665 BOOL fHPETEnabled;
1666 /* Other guests may wish to use HPET too, but MacOS X not functional without it */
1667 hrc = pMachine->COMGETTER(HPETEnabled)(&fHPETEnabled); H();
1668 /* so always enable HPET in extended profile */
1669 fHPETEnabled |= fOsXGuest;
1670 /* HPET is always present on ICH9 */
1671 fHPETEnabled |= (chipsetType == ChipsetType_ICH9);
1672 if (fHPETEnabled)
1673 {
1674 InsertConfigNode(pDevices, "hpet", &pDev);
1675 InsertConfigNode(pDev, "0", &pInst);
1676 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1677 InsertConfigNode(pInst, "Config", &pCfg);
1678 InsertConfigInteger(pCfg, "ICH9", (chipsetType == ChipsetType_ICH9) ? 1 : 0); /* boolean */
1679 }
1680
1681 /*
1682 * System Management Controller (SMC)
1683 */
1684 BOOL fSmcEnabled;
1685 fSmcEnabled = fOsXGuest;
1686 if (fSmcEnabled)
1687 {
1688 InsertConfigNode(pDevices, "smc", &pDev);
1689 InsertConfigNode(pDev, "0", &pInst);
1690 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1691 InsertConfigNode(pInst, "Config", &pCfg);
1692
1693 bool fGetKeyFromRealSMC;
1694 Utf8Str strKey;
1695 rc = getSmcDeviceKey(virtualBox, pMachine, &strKey, &fGetKeyFromRealSMC);
1696 AssertRCReturn(rc, rc);
1697
1698 if (!fGetKeyFromRealSMC)
1699 InsertConfigString(pCfg, "DeviceKey", strKey);
1700 InsertConfigInteger(pCfg, "GetKeyFromRealSMC", fGetKeyFromRealSMC);
1701 }
1702
1703 /*
1704 * Low Pin Count (LPC) bus
1705 */
1706 BOOL fLpcEnabled;
1707 /** @todo implement appropriate getter */
1708 fLpcEnabled = fOsXGuest || (chipsetType == ChipsetType_ICH9);
1709 if (fLpcEnabled)
1710 {
1711 InsertConfigNode(pDevices, "lpc", &pDev);
1712 InsertConfigNode(pDev, "0", &pInst);
1713 hrc = pBusMgr->assignPCIDevice("lpc", pInst); H();
1714 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1715 }
1716
1717 BOOL fShowRtc;
1718 fShowRtc = fOsXGuest || (chipsetType == ChipsetType_ICH9);
1719
1720 /*
1721 * PS/2 keyboard & mouse.
1722 */
1723 InsertConfigNode(pDevices, "pckbd", &pDev);
1724 InsertConfigNode(pDev, "0", &pInst);
1725 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1726 InsertConfigNode(pInst, "Config", &pCfg);
1727
1728 KeyboardHIDType_T aKbdHID;
1729 hrc = pMachine->COMGETTER(KeyboardHIDType)(&aKbdHID); H();
1730 if (aKbdHID != KeyboardHIDType_None)
1731 {
1732 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1733 InsertConfigString(pLunL0, "Driver", "KeyboardQueue");
1734 InsertConfigNode(pLunL0, "Config", &pCfg);
1735 InsertConfigInteger(pCfg, "QueueSize", 64);
1736
1737 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1738 InsertConfigString(pLunL1, "Driver", "MainKeyboard");
1739 }
1740
1741 PointingHIDType_T aPointingHID;
1742 hrc = pMachine->COMGETTER(PointingHIDType)(&aPointingHID); H();
1743 if (aPointingHID != PointingHIDType_None)
1744 {
1745 InsertConfigNode(pInst, "LUN#1", &pLunL0);
1746 InsertConfigString(pLunL0, "Driver", "MouseQueue");
1747 InsertConfigNode(pLunL0, "Config", &pCfg);
1748 InsertConfigInteger(pCfg, "QueueSize", 128);
1749
1750 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1751 InsertConfigString(pLunL1, "Driver", "MainMouse");
1752 }
1753
1754 /*
1755 * i8254 Programmable Interval Timer And Dummy Speaker
1756 */
1757 InsertConfigNode(pDevices, "i8254", &pDev);
1758 InsertConfigNode(pDev, "0", &pInst);
1759 InsertConfigNode(pInst, "Config", &pCfg);
1760#ifdef DEBUG
1761 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1762#endif
1763
1764 /*
1765 * i8259 Programmable Interrupt Controller.
1766 */
1767 InsertConfigNode(pDevices, "i8259", &pDev);
1768 InsertConfigNode(pDev, "0", &pInst);
1769 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1770 InsertConfigNode(pInst, "Config", &pCfg);
1771
1772 /*
1773 * Advanced Programmable Interrupt Controller.
1774 * SMP: Each CPU has a LAPIC, but we have a single device representing all LAPICs states,
1775 * thus only single insert
1776 */
1777 if (fEnableAPIC)
1778 {
1779 InsertConfigNode(pDevices, "apic", &pDev);
1780 InsertConfigNode(pDev, "0", &pInst);
1781 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1782 InsertConfigNode(pInst, "Config", &pCfg);
1783 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1784 PDMAPICMODE enmAPICMode = PDMAPICMODE_APIC;
1785 if (fEnableX2APIC)
1786 enmAPICMode = PDMAPICMODE_X2APIC;
1787 else if (!fEnableAPIC)
1788 enmAPICMode = PDMAPICMODE_NONE;
1789 InsertConfigInteger(pCfg, "Mode", enmAPICMode);
1790 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1791
1792 if (fIOAPIC)
1793 {
1794 /*
1795 * I/O Advanced Programmable Interrupt Controller.
1796 */
1797 InsertConfigNode(pDevices, "ioapic", &pDev);
1798 InsertConfigNode(pDev, "0", &pInst);
1799 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1800 InsertConfigNode(pInst, "Config", &pCfg);
1801 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1802 if (enmIommuType == IommuType_AMD)
1803 InsertConfigInteger(pCfg, "PCIAddress", uIoApicPciAddress);
1804 else if (enmIommuType == IommuType_Intel)
1805 {
1806 InsertConfigString(pCfg, "ChipType", "DMAR");
1807 InsertConfigInteger(pCfg, "PCIAddress", uIoApicPciAddress);
1808 }
1809 }
1810 }
1811
1812 /*
1813 * RTC MC146818.
1814 */
1815 InsertConfigNode(pDevices, "mc146818", &pDev);
1816 InsertConfigNode(pDev, "0", &pInst);
1817 InsertConfigNode(pInst, "Config", &pCfg);
1818 BOOL fRTCUseUTC;
1819 hrc = pMachine->COMGETTER(RTCUseUTC)(&fRTCUseUTC); H();
1820 InsertConfigInteger(pCfg, "UseUTC", fRTCUseUTC ? 1 : 0);
1821
1822 /*
1823 * VGA.
1824 */
1825 ComPtr<IGraphicsAdapter> pGraphicsAdapter;
1826 hrc = pMachine->COMGETTER(GraphicsAdapter)(pGraphicsAdapter.asOutParam()); H();
1827 GraphicsControllerType_T enmGraphicsController;
1828 hrc = pGraphicsAdapter->COMGETTER(GraphicsControllerType)(&enmGraphicsController); H();
1829 switch (enmGraphicsController)
1830 {
1831 case GraphicsControllerType_Null:
1832 break;
1833#ifdef VBOX_WITH_VMSVGA
1834 case GraphicsControllerType_VMSVGA:
1835 InsertConfigInteger(pHM, "LovelyMesaDrvWorkaround", 1); /* hits someone else logging backdoor. */
1836 InsertConfigInteger(pNEM, "LovelyMesaDrvWorkaround", 1); /* hits someone else logging backdoor. */
1837 RT_FALL_THROUGH();
1838 case GraphicsControllerType_VBoxSVGA:
1839#endif
1840 case GraphicsControllerType_VBoxVGA:
1841 rc = i_configGraphicsController(pDevices, enmGraphicsController, pBusMgr, pMachine, pGraphicsAdapter, biosSettings,
1842 RT_BOOL(fHMEnabled));
1843 if (FAILED(rc))
1844 return rc;
1845 break;
1846 default:
1847 AssertMsgFailed(("Invalid graphicsController=%d\n", enmGraphicsController));
1848 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1849 N_("Invalid graphics controller type '%d'"), enmGraphicsController);
1850 }
1851
1852 /*
1853 * Firmware.
1854 */
1855 FirmwareType_T eFwType = FirmwareType_BIOS;
1856 hrc = pMachine->COMGETTER(FirmwareType)(&eFwType); H();
1857
1858#ifdef VBOX_WITH_EFI
1859 BOOL fEfiEnabled = (eFwType >= FirmwareType_EFI) && (eFwType <= FirmwareType_EFIDUAL);
1860#else
1861 BOOL fEfiEnabled = false;
1862#endif
1863 if (!fEfiEnabled)
1864 {
1865 /*
1866 * PC Bios.
1867 */
1868 InsertConfigNode(pDevices, "pcbios", &pDev);
1869 InsertConfigNode(pDev, "0", &pInst);
1870 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1871 InsertConfigNode(pInst, "Config", &pBiosCfg);
1872 InsertConfigInteger(pBiosCfg, "NumCPUs", cCpus);
1873 InsertConfigString(pBiosCfg, "HardDiskDevice", "piix3ide");
1874 InsertConfigString(pBiosCfg, "FloppyDevice", "i82078");
1875 InsertConfigInteger(pBiosCfg, "IOAPIC", fIOAPIC);
1876 InsertConfigInteger(pBiosCfg, "APIC", uFwAPIC);
1877 BOOL fPXEDebug;
1878 hrc = biosSettings->COMGETTER(PXEDebugEnabled)(&fPXEDebug); H();
1879 InsertConfigInteger(pBiosCfg, "PXEDebug", fPXEDebug);
1880 InsertConfigBytes(pBiosCfg, "UUID", &HardwareUuid,sizeof(HardwareUuid));
1881 BOOL fUuidLe;
1882 hrc = biosSettings->COMGETTER(SMBIOSUuidLittleEndian)(&fUuidLe); H();
1883 InsertConfigInteger(pBiosCfg, "UuidLe", fUuidLe);
1884 InsertConfigNode(pBiosCfg, "NetBoot", &pNetBootCfg);
1885 InsertConfigInteger(pBiosCfg, "McfgBase", uMcfgBase);
1886 InsertConfigInteger(pBiosCfg, "McfgLength", cbMcfgLength);
1887
1888 AssertMsgReturn(SchemaDefs::MaxBootPosition <= 9, ("Too many boot devices %d\n", SchemaDefs::MaxBootPosition),
1889 VERR_INVALID_PARAMETER);
1890
1891 for (ULONG pos = 1; pos <= SchemaDefs::MaxBootPosition; ++pos)
1892 {
1893 DeviceType_T enmBootDevice;
1894 hrc = pMachine->GetBootOrder(pos, &enmBootDevice); H();
1895
1896 char szParamName[] = "BootDeviceX";
1897 szParamName[sizeof(szParamName) - 2] = (char)(pos - 1 + '0');
1898
1899 const char *pszBootDevice;
1900 switch (enmBootDevice)
1901 {
1902 case DeviceType_Null:
1903 pszBootDevice = "NONE";
1904 break;
1905 case DeviceType_HardDisk:
1906 pszBootDevice = "IDE";
1907 break;
1908 case DeviceType_DVD:
1909 pszBootDevice = "DVD";
1910 break;
1911 case DeviceType_Floppy:
1912 pszBootDevice = "FLOPPY";
1913 break;
1914 case DeviceType_Network:
1915 pszBootDevice = "LAN";
1916 break;
1917 default:
1918 AssertMsgFailed(("Invalid enmBootDevice=%d\n", enmBootDevice));
1919 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1920 N_("Invalid boot device '%d'"), enmBootDevice);
1921 }
1922 InsertConfigString(pBiosCfg, szParamName, pszBootDevice);
1923 }
1924
1925 /** @todo @bugref{7145}: We might want to enable this by default for new VMs. For now,
1926 * this is required for Windows 2012 guests. */
1927 if (osTypeId == "Windows2012_64")
1928 InsertConfigInteger(pBiosCfg, "DmiExposeMemoryTable", 1); /* boolean */
1929 }
1930 else
1931 {
1932 /* Autodetect firmware type, basing on guest type */
1933 if (eFwType == FirmwareType_EFI)
1934 eFwType = fIsGuest64Bit ? FirmwareType_EFI64 : FirmwareType_EFI32;
1935 bool const f64BitEntry = eFwType == FirmwareType_EFI64;
1936
1937 Assert(eFwType == FirmwareType_EFI64 || eFwType == FirmwareType_EFI32 || eFwType == FirmwareType_EFIDUAL);
1938#ifdef VBOX_WITH_EFI_IN_DD2
1939 const char *pszEfiRomFile = eFwType == FirmwareType_EFIDUAL ? "VBoxEFIDual.fd"
1940 : eFwType == FirmwareType_EFI32 ? "VBoxEFI32.fd"
1941 : "VBoxEFI64.fd";
1942#else
1943 Utf8Str efiRomFile;
1944 rc = findEfiRom(virtualBox, eFwType, &efiRomFile);
1945 AssertRCReturn(rc, rc);
1946 const char *pszEfiRomFile = efiRomFile.c_str();
1947#endif
1948
1949 /* Get boot args */
1950 Utf8Str bootArgs;
1951 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiBootArgs", &bootArgs);
1952
1953 /* Get device props */
1954 Utf8Str deviceProps;
1955 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiDeviceProps", &deviceProps);
1956
1957 /* Get NVRAM file name */
1958 Utf8Str strNvram = mptrNvramStore->i_getNonVolatileStorageFile();
1959
1960 BOOL fUuidLe;
1961 hrc = biosSettings->COMGETTER(SMBIOSUuidLittleEndian)(&fUuidLe); H();
1962
1963 /* Get graphics mode settings */
1964 uint32_t u32GraphicsMode = UINT32_MAX;
1965 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGraphicsMode", &strTmp);
1966 if (strTmp.isEmpty())
1967 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGopMode", &strTmp);
1968 if (!strTmp.isEmpty())
1969 u32GraphicsMode = strTmp.toUInt32();
1970
1971 /* Get graphics resolution settings, with some sanity checking */
1972 Utf8Str strResolution;
1973 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGraphicsResolution", &strResolution);
1974 if (!strResolution.isEmpty())
1975 {
1976 size_t pos = strResolution.find("x");
1977 if (pos != strResolution.npos)
1978 {
1979 Utf8Str strH, strV;
1980 strH.assignEx(strResolution, 0, pos);
1981 strV.assignEx(strResolution, pos+1, strResolution.length()-pos-1);
1982 uint32_t u32H = strH.toUInt32();
1983 uint32_t u32V = strV.toUInt32();
1984 if (u32H == 0 || u32V == 0)
1985 strResolution.setNull();
1986 }
1987 else
1988 strResolution.setNull();
1989 }
1990 else
1991 {
1992 uint32_t u32H = 0;
1993 uint32_t u32V = 0;
1994 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiHorizontalResolution", &strTmp);
1995 if (strTmp.isEmpty())
1996 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiUgaHorizontalResolution", &strTmp);
1997 if (!strTmp.isEmpty())
1998 u32H = strTmp.toUInt32();
1999
2000 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiVerticalResolution", &strTmp);
2001 if (strTmp.isEmpty())
2002 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiUgaVerticalResolution", &strTmp);
2003 if (!strTmp.isEmpty())
2004 u32V = strTmp.toUInt32();
2005 if (u32H != 0 && u32V != 0)
2006 strResolution = Utf8StrFmt("%ux%u", u32H, u32V);
2007 }
2008
2009 /*
2010 * EFI subtree.
2011 */
2012 InsertConfigNode(pDevices, "efi", &pDev);
2013 InsertConfigNode(pDev, "0", &pInst);
2014 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2015 InsertConfigNode(pInst, "Config", &pCfg);
2016 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
2017 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
2018 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
2019 InsertConfigString(pCfg, "EfiRom", pszEfiRomFile);
2020 InsertConfigString(pCfg, "BootArgs", bootArgs);
2021 InsertConfigString(pCfg, "DeviceProps", deviceProps);
2022 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
2023 InsertConfigInteger(pCfg, "APIC", uFwAPIC);
2024 InsertConfigBytes(pCfg, "UUID", &HardwareUuid,sizeof(HardwareUuid));
2025 InsertConfigInteger(pCfg, "UuidLe", fUuidLe);
2026 InsertConfigInteger(pCfg, "64BitEntry", f64BitEntry); /* boolean */
2027 InsertConfigString(pCfg, "NvramFile", strNvram);
2028 if (u32GraphicsMode != UINT32_MAX)
2029 InsertConfigInteger(pCfg, "GraphicsMode", u32GraphicsMode);
2030 if (!strResolution.isEmpty())
2031 InsertConfigString(pCfg, "GraphicsResolution", strResolution);
2032
2033 /* For OS X guests we'll force passing host's DMI info to the guest */
2034 if (fOsXGuest)
2035 {
2036 InsertConfigInteger(pCfg, "DmiUseHostInfo", 1);
2037 InsertConfigInteger(pCfg, "DmiExposeMemoryTable", 1);
2038 }
2039
2040 /* Attach the NVRAM storage driver. */
2041 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2042 InsertConfigString(pLunL0, "Driver", "NvramStore");
2043 }
2044
2045 /*
2046 * The USB Controllers.
2047 */
2048 com::SafeIfaceArray<IUSBController> usbCtrls;
2049 hrc = pMachine->COMGETTER(USBControllers)(ComSafeArrayAsOutParam(usbCtrls));
2050 bool fOhciPresent = false; /**< Flag whether at least one OHCI controller is present. */
2051 bool fXhciPresent = false; /**< Flag whether at least one XHCI controller is present. */
2052
2053 if (SUCCEEDED(hrc))
2054 {
2055 for (size_t i = 0; i < usbCtrls.size(); ++i)
2056 {
2057 USBControllerType_T enmCtrlType;
2058 rc = usbCtrls[i]->COMGETTER(Type)(&enmCtrlType); H();
2059 if (enmCtrlType == USBControllerType_OHCI)
2060 {
2061 fOhciPresent = true;
2062 break;
2063 }
2064 else if (enmCtrlType == USBControllerType_XHCI)
2065 {
2066 fXhciPresent = true;
2067 break;
2068 }
2069 }
2070 }
2071 else if (hrc != E_NOTIMPL)
2072 {
2073 H();
2074 }
2075
2076 /*
2077 * Currently EHCI is only enabled when an OHCI or XHCI controller is present as well.
2078 */
2079 if (fOhciPresent || fXhciPresent)
2080 mfVMHasUsbController = true;
2081
2082 PCFGMNODE pUsbDevices = NULL; /**< Required for USB storage controller later. */
2083 if (mfVMHasUsbController)
2084 {
2085 for (size_t i = 0; i < usbCtrls.size(); ++i)
2086 {
2087 USBControllerType_T enmCtrlType;
2088 rc = usbCtrls[i]->COMGETTER(Type)(&enmCtrlType); H();
2089
2090 if (enmCtrlType == USBControllerType_OHCI)
2091 {
2092 InsertConfigNode(pDevices, "usb-ohci", &pDev);
2093 InsertConfigNode(pDev, "0", &pInst);
2094 InsertConfigNode(pInst, "Config", &pCfg);
2095 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2096 hrc = pBusMgr->assignPCIDevice("usb-ohci", pInst); H();
2097 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2098 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
2099 InsertConfigNode(pLunL0, "Config", &pCfg);
2100
2101 /*
2102 * Attach the status driver.
2103 */
2104 i_attachStatusDriver(pInst, DeviceType_USB, 0, 0, NULL, NULL, NULL, 0);
2105 }
2106#ifdef VBOX_WITH_EHCI
2107 else if (enmCtrlType == USBControllerType_EHCI)
2108 {
2109 /*
2110 * USB 2.0 is only available if the proper ExtPack is installed.
2111 *
2112 * Note. Configuring EHCI here and providing messages about
2113 * the missing extpack isn't exactly clean, but it is a
2114 * necessary evil to patch over legacy compatability issues
2115 * introduced by the new distribution model.
2116 */
2117# ifdef VBOX_WITH_EXTPACK
2118 static const char *s_pszUsbExtPackName = "Oracle VM VirtualBox Extension Pack";
2119 if (mptrExtPackManager->i_isExtPackUsable(s_pszUsbExtPackName))
2120# endif
2121 {
2122 InsertConfigNode(pDevices, "usb-ehci", &pDev);
2123 InsertConfigNode(pDev, "0", &pInst);
2124 InsertConfigNode(pInst, "Config", &pCfg);
2125 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2126 hrc = pBusMgr->assignPCIDevice("usb-ehci", pInst); H();
2127
2128 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2129 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
2130 InsertConfigNode(pLunL0, "Config", &pCfg);
2131
2132 /*
2133 * Attach the status driver.
2134 */
2135 i_attachStatusDriver(pInst, DeviceType_USB, 0, 0, NULL, NULL, NULL, 0);
2136 }
2137# ifdef VBOX_WITH_EXTPACK
2138 else
2139 {
2140 /* Always fatal! Up to VBox 4.0.4 we allowed to start the VM anyway
2141 * but this induced problems when the user saved + restored the VM! */
2142 return pVMM->pfnVMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
2143 N_("Implementation of the USB 2.0 controller not found!\n"
2144 "Because the USB 2.0 controller state is part of the saved "
2145 "VM state, the VM cannot be started. To fix "
2146 "this problem, either install the '%s' or disable USB 2.0 "
2147 "support in the VM settings.\n"
2148 "Note! This error could also mean that an incompatible version of "
2149 "the '%s' is installed"),
2150 s_pszUsbExtPackName, s_pszUsbExtPackName);
2151 }
2152# endif
2153 }
2154#endif
2155 else if (enmCtrlType == USBControllerType_XHCI)
2156 {
2157 /*
2158 * USB 3.0 is only available if the proper ExtPack is installed.
2159 *
2160 * Note. Configuring EHCI here and providing messages about
2161 * the missing extpack isn't exactly clean, but it is a
2162 * necessary evil to patch over legacy compatability issues
2163 * introduced by the new distribution model.
2164 */
2165# ifdef VBOX_WITH_EXTPACK
2166 static const char *s_pszUsbExtPackName = "Oracle VM VirtualBox Extension Pack";
2167 if (mptrExtPackManager->i_isExtPackUsable(s_pszUsbExtPackName))
2168# endif
2169 {
2170 InsertConfigNode(pDevices, "usb-xhci", &pDev);
2171 InsertConfigNode(pDev, "0", &pInst);
2172 InsertConfigNode(pInst, "Config", &pCfg);
2173 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2174 hrc = pBusMgr->assignPCIDevice("usb-xhci", pInst); H();
2175
2176 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2177 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
2178 InsertConfigNode(pLunL0, "Config", &pCfg);
2179
2180 InsertConfigNode(pInst, "LUN#1", &pLunL1);
2181 InsertConfigString(pLunL1, "Driver", "VUSBRootHub");
2182 InsertConfigNode(pLunL1, "Config", &pCfg);
2183
2184 /*
2185 * Attach the status driver.
2186 */
2187 i_attachStatusDriver(pInst, DeviceType_USB, 0, 1, NULL, NULL, NULL, 0);
2188 }
2189# ifdef VBOX_WITH_EXTPACK
2190 else
2191 {
2192 /* Always fatal. */
2193 return pVMM->pfnVMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
2194 N_("Implementation of the USB 3.0 controller not found!\n"
2195 "Because the USB 3.0 controller state is part of the saved "
2196 "VM state, the VM cannot be started. To fix "
2197 "this problem, either install the '%s' or disable USB 3.0 "
2198 "support in the VM settings"),
2199 s_pszUsbExtPackName);
2200 }
2201# endif
2202 }
2203 } /* for every USB controller. */
2204
2205
2206 /*
2207 * Virtual USB Devices.
2208 */
2209 InsertConfigNode(pRoot, "USB", &pUsbDevices);
2210
2211#ifdef VBOX_WITH_USB
2212 {
2213 /*
2214 * Global USB options, currently unused as we'll apply the 2.0 -> 1.1 morphing
2215 * on a per device level now.
2216 */
2217 InsertConfigNode(pUsbDevices, "USBProxy", &pCfg);
2218 InsertConfigNode(pCfg, "GlobalConfig", &pCfg);
2219 // This globally enables the 2.0 -> 1.1 device morphing of proxied devices to keep windows quiet.
2220 //InsertConfigInteger(pCfg, "Force11Device", true);
2221 // The following breaks stuff, but it makes MSDs work in vista. (I include it here so
2222 // that it's documented somewhere.) Users needing it can use:
2223 // VBoxManage setextradata "myvm" "VBoxInternal/USB/USBProxy/GlobalConfig/Force11PacketSize" 1
2224 //InsertConfigInteger(pCfg, "Force11PacketSize", true);
2225 }
2226#endif
2227
2228#ifdef VBOX_WITH_USB_CARDREADER
2229 BOOL aEmulatedUSBCardReaderEnabled = FALSE;
2230 hrc = pMachine->COMGETTER(EmulatedUSBCardReaderEnabled)(&aEmulatedUSBCardReaderEnabled); H();
2231 if (aEmulatedUSBCardReaderEnabled)
2232 {
2233 InsertConfigNode(pUsbDevices, "CardReader", &pDev);
2234 InsertConfigNode(pDev, "0", &pInst);
2235 InsertConfigNode(pInst, "Config", &pCfg);
2236
2237 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2238# ifdef VBOX_WITH_USB_CARDREADER_TEST
2239 InsertConfigString(pLunL0, "Driver", "DrvDirectCardReader");
2240 InsertConfigNode(pLunL0, "Config", &pCfg);
2241# else
2242 InsertConfigString(pLunL0, "Driver", "UsbCardReader");
2243 InsertConfigNode(pLunL0, "Config", &pCfg);
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 Utf8StrFmt devicePath("%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);
6446 if (FAILED(hrc))
6447 {
6448 return pVMM->pfnVMR3SetError(pUVM, hrc, RT_SRC_POS,
6449 N_("Failed to start cloud gateway instance.\nMake sure you set up "
6450 "cloud networking properly with 'VBoxManage network setup'. "
6451 "Check VBoxSVC.log for details."));
6452 }
6453 InsertConfigBytes(pDevCfg, "MAC", &mGateway.mCloudMacAddress, sizeof(mGateway.mCloudMacAddress));
6454 if (!bstr.isEmpty())
6455 {
6456 InsertConfigString(pLunL0, "Driver", "CloudTunnel");
6457 InsertConfigNode(pLunL0, "Config", &pCfg);
6458 InsertConfigPassword(pCfg, "SshKey", mGateway.mPrivateSshKey);
6459 InsertConfigString(pCfg, "PrimaryIP", mGateway.mCloudPublicIp);
6460 InsertConfigString(pCfg, "SecondaryIP", mGateway.mCloudSecondaryPublicIp);
6461 InsertConfigBytes(pCfg, "TargetMAC", &mGateway.mLocalMacAddress, sizeof(mGateway.mLocalMacAddress));
6462 networkName = bstr;
6463 trunkType = Bstr(TRUNKTYPE_WHATEVER);
6464 }
6465 break;
6466 }
6467#endif /* VBOX_WITH_CLOUD_NET */
6468
6469#ifdef VBOX_WITH_VMNET
6470 case NetworkAttachmentType_HostOnlyNetwork:
6471 {
6472 Bstr bstrId, bstrNetMask, bstrLowerIP, bstrUpperIP;
6473 ComPtr<IHostOnlyNetwork> network;
6474 hrc = aNetworkAdapter->COMGETTER(HostOnlyNetwork)(bstr.asOutParam()); H();
6475 hrc = virtualBox->FindHostOnlyNetworkByName(bstr.raw(), network.asOutParam());
6476 if (FAILED(hrc))
6477 {
6478 LogRel(("NetworkAttachmentType_HostOnlyNetwork: FindByName failed, hrc (0x%x)\n", hrc));
6479 return pVMM->pfnVMR3SetError(pUVM, VERR_INTERNAL_ERROR, RT_SRC_POS,
6480 N_("Nonexistent host-only network '%ls'"), bstr.raw());
6481 }
6482 hrc = network->COMGETTER(Id)(bstrId.asOutParam()); H();
6483 hrc = network->COMGETTER(NetworkMask)(bstrNetMask.asOutParam()); H();
6484 hrc = network->COMGETTER(LowerIP)(bstrLowerIP.asOutParam()); H();
6485 hrc = network->COMGETTER(UpperIP)(bstrUpperIP.asOutParam()); H();
6486 if (!bstr.isEmpty())
6487 {
6488 InsertConfigString(pLunL0, "Driver", "VMNet");
6489 InsertConfigNode(pLunL0, "Config", &pCfg);
6490 // InsertConfigString(pCfg, "Trunk", Utf8Str(bstr).c_str());
6491 // InsertConfigString(pCfg, "Network", BstrFmt("HostOnlyNetworking-%ls", bstr.raw()));
6492 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
6493 InsertConfigString(pCfg, "Id", Utf8Str(bstrId).c_str());
6494 InsertConfigString(pCfg, "NetworkMask", Utf8Str(bstrNetMask).c_str());
6495 InsertConfigString(pCfg, "LowerIP", Utf8Str(bstrLowerIP).c_str());
6496 InsertConfigString(pCfg, "UpperIP", Utf8Str(bstrUpperIP).c_str());
6497 // InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
6498 networkName.setNull(); // We do not want DHCP server on our network!
6499 // trunkType = Bstr(TRUNKTYPE_WHATEVER);
6500 }
6501 break;
6502 }
6503#endif /* VBOX_WITH_VMNET */
6504
6505 default:
6506 AssertMsgFailed(("should not get here!\n"));
6507 break;
6508 }
6509
6510 /*
6511 * Attempt to attach the driver.
6512 */
6513 switch (eAttachmentType)
6514 {
6515 case NetworkAttachmentType_Null:
6516 break;
6517
6518 case NetworkAttachmentType_Bridged:
6519 case NetworkAttachmentType_Internal:
6520 case NetworkAttachmentType_HostOnly:
6521#ifdef VBOX_WITH_VMNET
6522 case NetworkAttachmentType_HostOnlyNetwork:
6523#endif /* VBOX_WITH_VMNET */
6524 case NetworkAttachmentType_NAT:
6525 case NetworkAttachmentType_Generic:
6526 case NetworkAttachmentType_NATNetwork:
6527#ifdef VBOX_WITH_CLOUD_NET
6528 case NetworkAttachmentType_Cloud:
6529#endif /* VBOX_WITH_CLOUD_NET */
6530 {
6531 if (SUCCEEDED(hrc) && RT_SUCCESS(rc))
6532 {
6533 if (fAttachDetach)
6534 {
6535 rc = pVMM->pfnPDMR3DriverAttach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/, NULL /* ppBase */);
6536 //AssertRC(rc);
6537 }
6538
6539 {
6540 /** @todo pritesh: get the dhcp server name from the
6541 * previous network configuration and then stop the server
6542 * else it may conflict with the dhcp server running with
6543 * the current attachment type
6544 */
6545 /* Stop the hostonly DHCP Server */
6546 }
6547
6548 /*
6549 * NAT networks start their DHCP server theirself, see NATNetwork::Start()
6550 */
6551 if ( !networkName.isEmpty()
6552 && eAttachmentType != NetworkAttachmentType_NATNetwork)
6553 {
6554 /*
6555 * Until we implement service reference counters DHCP Server will be stopped
6556 * by DHCPServerRunner destructor.
6557 */
6558 ComPtr<IDHCPServer> dhcpServer;
6559 hrc = virtualBox->FindDHCPServerByNetworkName(networkName.raw(), dhcpServer.asOutParam());
6560 if (SUCCEEDED(hrc))
6561 {
6562 /* there is a DHCP server available for this network */
6563 BOOL fEnabledDhcp;
6564 hrc = dhcpServer->COMGETTER(Enabled)(&fEnabledDhcp);
6565 if (FAILED(hrc))
6566 {
6567 LogRel(("DHCP svr: COMGETTER(Enabled) failed, hrc (%Rhrc)\n", hrc));
6568 H();
6569 }
6570
6571 if (fEnabledDhcp)
6572 hrc = dhcpServer->Start(trunkName.raw(), trunkType.raw());
6573 }
6574 else
6575 hrc = S_OK;
6576 }
6577 }
6578
6579 break;
6580 }
6581
6582 default:
6583 AssertMsgFailed(("should not get here!\n"));
6584 break;
6585 }
6586
6587 meAttachmentType[uInstance] = eAttachmentType;
6588 }
6589 catch (ConfigError &x)
6590 {
6591 // InsertConfig threw something:
6592 return x.m_vrc;
6593 }
6594
6595#undef H
6596
6597 return VINF_SUCCESS;
6598}
6599
6600
6601/**
6602 * Configures the serial port at the given CFGM node with the supplied parameters.
6603 *
6604 * @returns VBox status code.
6605 * @param pInst The instance CFGM node.
6606 * @param ePortMode The port mode to sue.
6607 * @param pszPath The serial port path.
6608 * @param fServer Flag whether the port should act as a server
6609 * for the pipe and TCP mode or connect as a client.
6610 */
6611int Console::i_configSerialPort(PCFGMNODE pInst, PortMode_T ePortMode, const char *pszPath, bool fServer)
6612{
6613 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
6614 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */
6615 PCFGMNODE pLunL1Cfg = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/Config */
6616
6617 try
6618 {
6619 InsertConfigNode(pInst, "LUN#0", &pLunL0);
6620 if (ePortMode == PortMode_HostPipe)
6621 {
6622 InsertConfigString(pLunL0, "Driver", "Char");
6623 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
6624 InsertConfigString(pLunL1, "Driver", "NamedPipe");
6625 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
6626 InsertConfigString(pLunL1Cfg, "Location", pszPath);
6627 InsertConfigInteger(pLunL1Cfg, "IsServer", fServer);
6628 }
6629 else if (ePortMode == PortMode_HostDevice)
6630 {
6631 InsertConfigString(pLunL0, "Driver", "Host Serial");
6632 InsertConfigNode(pLunL0, "Config", &pLunL1);
6633 InsertConfigString(pLunL1, "DevicePath", pszPath);
6634 }
6635 else if (ePortMode == PortMode_TCP)
6636 {
6637 InsertConfigString(pLunL0, "Driver", "Char");
6638 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
6639 InsertConfigString(pLunL1, "Driver", "TCP");
6640 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
6641 InsertConfigString(pLunL1Cfg, "Location", pszPath);
6642 InsertConfigInteger(pLunL1Cfg, "IsServer", fServer);
6643 }
6644 else if (ePortMode == PortMode_RawFile)
6645 {
6646 InsertConfigString(pLunL0, "Driver", "Char");
6647 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
6648 InsertConfigString(pLunL1, "Driver", "RawFile");
6649 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
6650 InsertConfigString(pLunL1Cfg, "Location", pszPath);
6651 }
6652 }
6653 catch (ConfigError &x)
6654 {
6655 /* InsertConfig threw something */
6656 return x.m_vrc;
6657 }
6658
6659 return VINF_SUCCESS;
6660}
6661
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use