VirtualBox

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

Last change on this file since 96477 was 96407, checked in by vboxsync, 22 months ago

scm copyright and license note update

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

© 2023 Oracle
ContactPrivacy policyTerms of Use