VirtualBox

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

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

Main/ConsoleImpl2.cpp: Look at the CPU profile then the host cpu vendor when resolving IommuType_Automatic, skipping the latter for non-x86 hosts. bugref:9898

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

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