VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/ConsoleImplConfigCommon.cpp@ 107928

Last change on this file since 107928 was 107928, checked in by vboxsync, 4 months ago

Audio/Main: Added some logging when selecting the DirectSound backend on Windows hosts that now the Windows Audio Session (WAS) backend is being used instead of DirectSound for performance reasons (unless explicitly specified via extra data).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 225.9 KB
Line 
1/* $Id: ConsoleImplConfigCommon.cpp 107928 2025-01-24 08:43:36Z 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-2024 Oracle and/or its affiliates.
13 *
14 * This file is part of VirtualBox base platform packages, as
15 * available from https://www.215389.xyz.
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#include "BusAssignmentManager.h"
50#ifdef VBOX_WITH_SHARED_CLIPBOARD
51# include "GuestShClPrivate.h"
52#endif
53#ifdef VBOX_WITH_DRAG_AND_DROP
54# include "GuestImpl.h"
55# include "GuestDnDPrivate.h"
56#endif
57#include "VMMDev.h"
58#include "Global.h"
59#ifdef VBOX_WITH_PCI_PASSTHROUGH
60# include "PCIRawDevImpl.h"
61#endif
62
63// generated header
64#include "SchemaDefs.h"
65
66#include "AutoCaller.h"
67
68#include <iprt/base64.h>
69#include <iprt/buildconfig.h>
70#include <iprt/ctype.h>
71#include <iprt/dir.h>
72#include <iprt/file.h>
73#include <iprt/param.h>
74#include <iprt/path.h>
75#include <iprt/string.h>
76#include <iprt/system.h>
77#if 0 /* enable to play with lots of memory. */
78# include <iprt/env.h>
79#endif
80#include <iprt/stream.h>
81
82#include <iprt/http.h>
83#include <iprt/socket.h>
84#include <iprt/uri.h>
85
86#include <VBox/vmm/vmmr3vtable.h>
87#include <VBox/vmm/vmapi.h>
88#include <VBox/err.h>
89#include <VBox/param.h>
90#include <VBox/settings.h> /* For MachineConfigFile::getHostDefaultAudioDriver(). */
91#include <VBox/vmm/pdmapi.h> /* For PDMR3DriverAttach/PDMR3DriverDetach. */
92#include <VBox/vmm/pdmusb.h> /* For PDMR3UsbCreateEmulatedDevice. */
93#include <VBox/vmm/pdmdev.h> /* For PDMAPICMODE enum. */
94#include <VBox/vmm/pdmstorageifs.h>
95#include <VBox/version.h>
96#ifdef VBOX_WITH_SHARED_CLIPBOARD
97# include <VBox/HostServices/VBoxClipboardSvc.h>
98#endif
99#ifdef VBOX_WITH_GUEST_PROPS
100# include <VBox/HostServices/GuestPropertySvc.h>
101# include <VBox/com/defs.h>
102# include <VBox/com/array.h>
103# include <vector>
104#endif /* VBOX_WITH_GUEST_PROPS */
105#include <VBox/intnet.h>
106
107#include <VBox/com/com.h>
108#include <VBox/com/string.h>
109#include <VBox/com/array.h>
110
111#ifdef VBOX_WITH_NETFLT
112# if defined(RT_OS_SOLARIS)
113# include <zone.h>
114# elif defined(RT_OS_LINUX)
115# include <unistd.h>
116# include <sys/ioctl.h>
117# include <sys/socket.h>
118# include <linux/types.h>
119# include <linux/if.h>
120# elif defined(RT_OS_FREEBSD)
121# include <unistd.h>
122# include <sys/types.h>
123# include <sys/ioctl.h>
124# include <sys/socket.h>
125# include <net/if.h>
126# include <net80211/ieee80211_ioctl.h>
127# endif
128# if defined(RT_OS_WINDOWS)
129# include <iprt/win/ntddndis.h>
130# include <devguid.h>
131# else
132# include <HostNetworkInterfaceImpl.h>
133# include <netif.h>
134# include <stdlib.h>
135# endif
136#endif /* VBOX_WITH_NETFLT */
137
138#ifdef VBOX_WITH_AUDIO_VRDE
139# include "DrvAudioVRDE.h"
140#endif
141#ifdef VBOX_WITH_AUDIO_RECORDING
142# include "DrvAudioRec.h"
143#endif
144#include "NetworkServiceRunner.h"
145#ifdef VBOX_WITH_EXTPACK
146# include "ExtPackManagerImpl.h"
147#endif
148
149
150/*********************************************************************************************************************************
151* Internal Functions *
152*********************************************************************************************************************************/
153
154/* Darwin compile kludge */
155#undef PVM
156
157/**
158 * Helper that calls CFGMR3InsertString and throws an RTCError if that
159 * fails (C-string variant).
160 * @param pNode See CFGMR3InsertString.
161 * @param pcszName See CFGMR3InsertString.
162 * @param pcszValue The string value.
163 */
164void Console::InsertConfigString(PCFGMNODE pNode, const char *pcszName, const char *pcszValue)
165{
166 int vrc = mpVMM->pfnCFGMR3InsertString(pNode, pcszName, pcszValue);
167 if (RT_FAILURE(vrc))
168 throw ConfigError("CFGMR3InsertString", vrc, pcszName);
169}
170
171/**
172 * Helper that calls CFGMR3InsertString and throws an RTCError if that
173 * fails (Utf8Str variant).
174 * @param pNode See CFGMR3InsertStringN.
175 * @param pcszName See CFGMR3InsertStringN.
176 * @param rStrValue The string value.
177 */
178void Console::InsertConfigString(PCFGMNODE pNode, const char *pcszName, const Utf8Str &rStrValue)
179{
180 int vrc = mpVMM->pfnCFGMR3InsertStringN(pNode, pcszName, rStrValue.c_str(), rStrValue.length());
181 if (RT_FAILURE(vrc))
182 throw ConfigError("CFGMR3InsertStringLengthKnown", vrc, pcszName);
183}
184
185/**
186 * Helper that calls CFGMR3InsertString and throws an RTCError if that
187 * fails (Bstr variant).
188 *
189 * @param pNode See CFGMR3InsertStringN.
190 * @param pcszName See CFGMR3InsertStringN.
191 * @param rBstrValue The string value.
192 */
193void Console::InsertConfigString(PCFGMNODE pNode, const char *pcszName, const Bstr &rBstrValue)
194{
195 InsertConfigString(pNode, pcszName, Utf8Str(rBstrValue));
196}
197
198/**
199 * Helper that calls CFGMR3InsertStringFV and throws an RTCError if that fails.
200 * @param pNode See CFGMR3InsertStringF.
201 * @param pcszName See CFGMR3InsertStringF.
202 * @param pszFormat See CFGMR3InsertStringF.
203 * @param ... See CFGMR3InsertStringF.
204 */
205void Console::InsertConfigStringF(PCFGMNODE pNode, const char *pcszName, const char *pszFormat, ...)
206{
207 va_list va;
208 va_start(va, pszFormat);
209 int vrc = mpVMM->pfnCFGMR3InsertStringFV(pNode, pcszName, pszFormat, va);
210 va_end(va);
211 if (RT_FAILURE(vrc))
212 throw ConfigError("CFGMR3InsertStringFV", vrc, pcszName);
213}
214
215
216/**
217 * Helper that calls CFGMR3InsertPassword and throws an RTCError if that
218 * fails (Utf8Str variant).
219 * @param pNode See CFGMR3InsertPasswordN.
220 * @param pcszName See CFGMR3InsertPasswordN.
221 * @param rStrValue The string value.
222 */
223void Console::InsertConfigPassword(PCFGMNODE pNode, const char *pcszName, const Utf8Str &rStrValue)
224{
225 int vrc = mpVMM->pfnCFGMR3InsertPasswordN(pNode, pcszName, rStrValue.c_str(), rStrValue.length());
226 if (RT_FAILURE(vrc))
227 throw ConfigError("CFGMR3InsertPasswordLengthKnown", vrc, pcszName);
228}
229
230/**
231 * Helper that calls CFGMR3InsertBytes and throws an RTCError if that fails.
232 *
233 * @param pNode See CFGMR3InsertBytes.
234 * @param pcszName See CFGMR3InsertBytes.
235 * @param pvBytes See CFGMR3InsertBytes.
236 * @param cbBytes See CFGMR3InsertBytes.
237 */
238void Console::InsertConfigBytes(PCFGMNODE pNode, const char *pcszName, const void *pvBytes, size_t cbBytes)
239{
240 int vrc = mpVMM->pfnCFGMR3InsertBytes(pNode, pcszName, pvBytes, cbBytes);
241 if (RT_FAILURE(vrc))
242 throw ConfigError("CFGMR3InsertBytes", vrc, pcszName);
243}
244
245/**
246 * Helper that calls CFGMR3InsertInteger and throws an RTCError if that
247 * fails.
248 *
249 * @param pNode See CFGMR3InsertInteger.
250 * @param pcszName See CFGMR3InsertInteger.
251 * @param u64Integer See CFGMR3InsertInteger.
252 */
253void Console::InsertConfigInteger(PCFGMNODE pNode, const char *pcszName, uint64_t u64Integer)
254{
255 int vrc = mpVMM->pfnCFGMR3InsertInteger(pNode, pcszName, u64Integer);
256 if (RT_FAILURE(vrc))
257 throw ConfigError("CFGMR3InsertInteger", vrc, pcszName);
258}
259
260/**
261 * Helper that calls CFGMR3InsertNode and throws an RTCError if that fails.
262 *
263 * @param pNode See CFGMR3InsertNode.
264 * @param pcszName See CFGMR3InsertNode.
265 * @param ppChild See CFGMR3InsertNode.
266 */
267void Console::InsertConfigNode(PCFGMNODE pNode, const char *pcszName, PCFGMNODE *ppChild)
268{
269 int vrc = mpVMM->pfnCFGMR3InsertNode(pNode, pcszName, ppChild);
270 if (RT_FAILURE(vrc))
271 throw ConfigError("CFGMR3InsertNode", vrc, pcszName);
272}
273
274/**
275 * Helper that calls CFGMR3InsertNodeF and throws an RTCError if that fails.
276 *
277 * @param pNode See CFGMR3InsertNodeF.
278 * @param ppChild See CFGMR3InsertNodeF.
279 * @param pszNameFormat Name format string, see CFGMR3InsertNodeF.
280 * @param ... Format arguments.
281 */
282void Console::InsertConfigNodeF(PCFGMNODE pNode, PCFGMNODE *ppChild, const char *pszNameFormat, ...)
283{
284 va_list va;
285 va_start(va, pszNameFormat);
286 int vrc = mpVMM->pfnCFGMR3InsertNodeF(pNode, ppChild, "%N", pszNameFormat, &va);
287 va_end(va);
288 if (RT_FAILURE(vrc))
289 throw ConfigError("CFGMR3InsertNodeF", vrc, pszNameFormat);
290}
291
292/**
293 * Helper that calls CFGMR3RemoveValue and throws an RTCError if that fails.
294 *
295 * @param pNode See CFGMR3RemoveValue.
296 * @param pcszName See CFGMR3RemoveValue.
297 */
298void Console::RemoveConfigValue(PCFGMNODE pNode, const char *pcszName)
299{
300 int vrc = mpVMM->pfnCFGMR3RemoveValue(pNode, pcszName);
301 if (RT_FAILURE(vrc))
302 throw ConfigError("CFGMR3RemoveValue", vrc, pcszName);
303}
304
305/**
306 * Gets an extra data value, consulting both machine and global extra data.
307 *
308 * @throws HRESULT on failure
309 * @returns pStrValue for the callers convenience.
310 * @param pVirtualBox Pointer to the IVirtualBox interface.
311 * @param pMachine Pointer to the IMachine interface.
312 * @param pszName The value to get.
313 * @param pStrValue Where to return it's value (empty string if not
314 * found).
315 */
316DECL_HIDDEN_THROW(Utf8Str *) GetExtraDataBoth(IVirtualBox *pVirtualBox, IMachine *pMachine, const char *pszName, Utf8Str *pStrValue)
317{
318 pStrValue->setNull();
319
320 Bstr bstrName(pszName);
321 Bstr bstrValue;
322 HRESULT hrc = pMachine->GetExtraData(bstrName.raw(), bstrValue.asOutParam());
323 if (FAILED(hrc))
324 throw hrc;
325 if (bstrValue.isEmpty())
326 {
327 hrc = pVirtualBox->GetExtraData(bstrName.raw(), bstrValue.asOutParam());
328 if (FAILED(hrc))
329 throw hrc;
330 }
331
332 if (bstrValue.isNotEmpty())
333 *pStrValue = bstrValue;
334 return pStrValue;
335}
336
337
338/**
339 * Updates the device type for a LED.
340 *
341 * @param penmSubTypeEntry The sub-type entry to update.
342 * @param enmNewType The new type.
343 */
344void Console::i_setLedType(DeviceType_T *penmSubTypeEntry, DeviceType_T enmNewType)
345{
346 /*
347 * ASSUMES no race conditions here wrt concurrent type updating.
348 */
349 if (*penmSubTypeEntry != enmNewType)
350 {
351 *penmSubTypeEntry = enmNewType;
352 ASMAtomicIncU32(&muLedGen);
353 }
354}
355
356
357/**
358 * Allocate a set of LEDs.
359 *
360 * This grabs a maLedSets entry and populates it with @a cLeds.
361 *
362 * @returns Index into maLedSets.
363 * @param cLeds The number of LEDs in the set.
364 * @param fTypes Bitmask of DeviceType_T values, e.g.
365 * RT_BIT_32(DeviceType_Network).
366 * @param ppaSubTypes When not NULL, subtypes for each LED and return the
367 * array pointer here.
368 */
369uint32_t Console::i_allocateDriverLeds(uint32_t cLeds, uint32_t fTypes, DeviceType_T **ppaSubTypes)
370{
371 Assert(cLeds > 0);
372 Assert(cLeds < 1024); /* Adjust if any driver supports >=1024 units! */
373 Assert(!(fTypes & (RT_BIT_32(DeviceType_Null) | ~(RT_BIT_32(DeviceType_End) - 1))));
374
375 /* Preallocate the arrays we need, bunching them together. */
376 AssertCompile((unsigned)DeviceType_Null == 0);
377 PPDMLED volatile *papLeds = (PPDMLED volatile *)RTMemAllocZ( (sizeof(PPDMLED) + (ppaSubTypes ? sizeof(**ppaSubTypes) : 0))
378 * cLeds);
379 AssertStmt(papLeds, throw E_OUTOFMEMORY);
380
381 /* Take the LED lock in allocation mode and see if there are more LED set entries availalbe. */
382 {
383 AutoWriteLock alock(mLedLock COMMA_LOCKVAL_SRC_POS);
384 uint32_t const idxLedSet = mcLedSets;
385 if (idxLedSet < RT_ELEMENTS(maLedSets))
386 {
387 /* Initialize the set and return the index. */
388 PLEDSET pLS = &maLedSets[idxLedSet];
389 pLS->papLeds = papLeds;
390 pLS->cLeds = cLeds;
391 pLS->fTypes = fTypes;
392 if (ppaSubTypes)
393 *ppaSubTypes = pLS->paSubTypes = (DeviceType_T *)&papLeds[cLeds];
394 else
395 pLS->paSubTypes = NULL;
396
397 mcLedSets = idxLedSet + 1;
398 LogRel2(("return idxLedSet=%d (mcLedSets=%u out of max %zu)\n", idxLedSet, mcLedSets, RT_ELEMENTS(maLedSets)));
399 return idxLedSet;
400 }
401 }
402
403 RTMemFree((void *)papLeds);
404 AssertFailed();
405 throw ConfigError("AllocateDriverPapLeds", VERR_OUT_OF_RANGE, "Too many LED sets");
406}
407
408
409/**
410 * @throws ConfigError and std::bad_alloc.
411 */
412void Console::i_attachStatusDriver(PCFGMNODE pCtlInst, uint32_t fTypes, uint32_t cLeds, DeviceType_T **ppaSubTypes,
413 Console::MediumAttachmentMap *pmapMediumAttachments,
414 const char *pcszDevice, unsigned uInstance)
415{
416 PCFGMNODE pLunL0;
417 InsertConfigNode(pCtlInst, "LUN#999", &pLunL0);
418 InsertConfigString(pLunL0, "Driver", "MainStatus");
419 PCFGMNODE pCfg;
420 InsertConfigNode(pLunL0, "Config", &pCfg);
421 uint32_t const iLedSet = i_allocateDriverLeds(cLeds, fTypes, ppaSubTypes);
422 InsertConfigInteger(pCfg, "iLedSet", iLedSet);
423
424 InsertConfigInteger(pCfg, "HasMediumAttachments", pmapMediumAttachments != NULL);
425 if (pmapMediumAttachments)
426 {
427 AssertPtr(pcszDevice);
428 InsertConfigStringF(pCfg, "DeviceInstance", "%s/%u", pcszDevice, uInstance);
429 }
430 InsertConfigInteger(pCfg, "First", 0);
431 InsertConfigInteger(pCfg, "Last", cLeds - 1);
432}
433
434
435/**
436 * @throws ConfigError and std::bad_alloc.
437 */
438void Console::i_attachStatusDriver(PCFGMNODE pCtlInst, DeviceType_T enmType, uint32_t cLeds /*= 1*/)
439{
440 Assert(enmType > DeviceType_Null && enmType < DeviceType_End);
441 i_attachStatusDriver(pCtlInst, RT_BIT_32(enmType), cLeds, NULL, NULL, NULL, 0);
442}
443
444
445/**
446 * Construct the VM configuration tree (CFGM).
447 *
448 * This is a callback for VMR3Create() call. It is called from CFGMR3Init() in
449 * the emulation thread (EMT). Any per thread COM/XPCOM initialization is done
450 * here.
451 *
452 * @returns VBox status code.
453 * @param pUVM The user mode VM handle.
454 * @param pVM The cross context VM handle.
455 * @param pVMM The VMM ring-3 vtable.
456 * @param pvConsole Pointer to the VMPowerUpTask object.
457 *
458 * @note Locks the Console object for writing.
459 */
460/*static*/ DECLCALLBACK(int)
461Console::i_configConstructor(PUVM pUVM, PVM pVM, PCVMMR3VTABLE pVMM, void *pvConsole)
462{
463 LogFlowFuncEnter();
464
465 AssertReturn(pvConsole, VERR_INVALID_POINTER);
466 ComObjPtr<Console> pConsole = static_cast<Console *>(pvConsole);
467
468 AutoCaller autoCaller(pConsole);
469 AssertComRCReturn(autoCaller.hrc(), VERR_ACCESS_DENIED);
470
471 /* lock the console because we widely use internal fields and methods */
472 AutoWriteLock alock(pConsole COMMA_LOCKVAL_SRC_POS);
473
474 /*
475 * Set the VM handle and do the rest of the job in an worker method so we
476 * can easily reset the VM handle on failure.
477 */
478 pConsole->mpUVM = pUVM;
479 pVMM->pfnVMR3RetainUVM(pUVM);
480 int vrc;
481 try
482 {
483 vrc = pConsole->i_configConstructorInner(pUVM, pVM, pVMM, &alock);
484 }
485 catch (...)
486 {
487 vrc = VERR_UNEXPECTED_EXCEPTION;
488 }
489 if (RT_FAILURE(vrc))
490 {
491 pConsole->mpUVM = NULL;
492 pVMM->pfnVMR3ReleaseUVM(pUVM);
493 }
494
495 return vrc;
496}
497
498
499/**
500 * Worker for configConstructor.
501 *
502 * @return VBox status code.
503 * @return VERR_PLATFORM_ARCH_NOT_SUPPORTED if the machine's platform architecture is not supported.
504 * @param pUVM The user mode VM handle.
505 * @param pVM The cross context VM handle.
506 * @param pVMM The VMM vtable.
507 * @param pAlock The automatic lock instance. This is for when we have
508 * to leave it in order to avoid deadlocks (ext packs and
509 * more).
510 */
511int Console::i_configConstructorInner(PUVM pUVM, PVM pVM, PCVMMR3VTABLE pVMM, AutoWriteLock *pAlock)
512{
513 ComPtr<IMachine> const pMachine = i_machine();
514
515 ComPtr<IPlatform> pPlatform;
516 HRESULT hrc = pMachine->COMGETTER(Platform)(pPlatform.asOutParam());
517 AssertComRCReturn(hrc, VERR_COM_VM_ERROR);
518
519 PlatformArchitecture_T platformArch;
520 hrc = pPlatform->COMGETTER(Architecture)(&platformArch);
521 AssertComRCReturn(hrc, VERR_COM_VM_ERROR);
522
523 switch (platformArch)
524 {
525 case PlatformArchitecture_x86:
526 return i_configConstructorX86(pUVM, pVM, pVMM, pAlock);
527
528#ifdef VBOX_WITH_VIRT_ARMV8
529 case PlatformArchitecture_ARM:
530 return i_configConstructorArmV8(pUVM, pVM, pVMM, pAlock);
531#endif
532 default:
533 break;
534 }
535
536 return VERR_PLATFORM_ARCH_NOT_SUPPORTED;
537}
538
539
540/**
541 * Configures an audio driver via CFGM by getting (optional) values from extra data.
542 *
543 * @param pVirtualBox Pointer to IVirtualBox instance.
544 * @param pMachine Pointer to IMachine instance.
545 * @param pLUN Pointer to CFGM node of LUN (the driver) to configure.
546 * @param pszDrvName Name of the driver to configure.
547 * @param fAudioEnabledIn IAudioAdapter::enabledIn value.
548 * @param fAudioEnabledOut IAudioAdapter::enabledOut value.
549 *
550 * @throws ConfigError or HRESULT on if there is trouble.
551 */
552void Console::i_configAudioDriver(IVirtualBox *pVirtualBox, IMachine *pMachine, PCFGMNODE pLUN, const char *pszDrvName,
553 bool fAudioEnabledIn, bool fAudioEnabledOut)
554{
555#define H() AssertLogRelMsgStmt(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), \
556 throw ConfigError(__FUNCTION__, VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR, "line: " RT_XSTR(__LINE__)))
557
558 InsertConfigString(pLUN, "Driver", "AUDIO");
559
560 PCFGMNODE pCfg;
561 InsertConfigNode(pLUN, "Config", &pCfg);
562 InsertConfigString(pCfg, "DriverName", pszDrvName);
563 InsertConfigInteger(pCfg, "InputEnabled", fAudioEnabledIn);
564 InsertConfigInteger(pCfg, "OutputEnabled", fAudioEnabledOut);
565
566 Utf8Str strTmp;
567 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/Audio/Debug/Enabled", &strTmp);
568 const uint64_t fDebugEnabled = strTmp.equalsIgnoreCase("true") || strTmp.equalsIgnoreCase("1");
569 if (fDebugEnabled)
570 {
571 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
572
573 Utf8Str strDebugPathOut;
574 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/Audio/Debug/PathOut", &strDebugPathOut);
575 InsertConfigString(pCfg, "DebugPathOut", strDebugPathOut.c_str());
576 }
577
578 /*
579 * PCM input parameters (playback + recording).
580 * We have host driver specific ones as: VBoxInternal2/Audio/<DrvName>/<Value>
581 * And global ones for all host drivers: VBoxInternal2/Audio/<Value>
582 */
583 for (unsigned iDir = 0; iDir < 2; iDir++)
584 {
585 static const struct
586 {
587 const char *pszExtraName;
588 const char *pszCfgmName;
589 } s_aToCopy[] =
590 { /* PCM parameters: */
591 { "PCMSampleBit", "PCMSampleBit" },
592 { "PCMSampleHz", "PCMSampleHz" },
593 { "PCMSampleSigned", "PCMSampleSigned" },
594 { "PCMSampleSwapEndian", "PCMSampleSwapEndian" },
595 { "PCMSampleChannels", "PCMSampleChannels" },
596 /* Buffering stuff: */
597 { "PeriodSizeMs", "PeriodSizeMs" },
598 { "BufferSizeMs", "BufferSizeMs" },
599 { "PreBufferSizeMs", "PreBufferSizeMs" },
600 };
601
602 PCFGMNODE pDirNode = NULL;
603 const char *pszDir = iDir == 0 ? "In" : "Out";
604 for (size_t i = 0; i < RT_ELEMENTS(s_aToCopy); i++)
605 {
606 char szExtra[128];
607 RTStrPrintf(szExtra, sizeof(szExtra), "VBoxInternal2/Audio/%s/%s%s", pszDrvName, s_aToCopy[i].pszExtraName, pszDir);
608 GetExtraDataBoth(pVirtualBox, pMachine, szExtra, &strTmp); /* throws hrc */
609 if (strTmp.isEmpty())
610 {
611 RTStrPrintf(szExtra, sizeof(szExtra), "VBoxInternal2/Audio/%s%s", s_aToCopy[i].pszExtraName, pszDir);
612 GetExtraDataBoth(pVirtualBox, pMachine, szExtra, &strTmp);
613 if (strTmp.isEmpty())
614 continue;
615 }
616
617 uint32_t uValue;
618 int vrc = RTStrToUInt32Full(strTmp.c_str(), 0, &uValue);
619 if (RT_SUCCESS(vrc))
620 {
621 if (!pDirNode)
622 InsertConfigNode(pCfg, pszDir, &pDirNode);
623 InsertConfigInteger(pDirNode, s_aToCopy[i].pszCfgmName, uValue);
624 }
625 else
626 LogRel(("Ignoring malformed 32-bit unsigned integer config value '%s' = '%s': %Rrc\n", szExtra, strTmp.c_str(), vrc));
627 }
628 }
629
630 PCFGMNODE pLunL1;
631 InsertConfigNode(pLUN, "AttachedDriver", &pLunL1);
632 InsertConfigString(pLunL1, "Driver", pszDrvName);
633 InsertConfigNode(pLunL1, "Config", &pCfg);
634
635#ifdef RT_OS_WINDOWS
636 if (strcmp(pszDrvName, "HostAudioWas") == 0)
637 {
638 Bstr bstrTmp;
639 HRESULT hrc = pMachine->COMGETTER(Id)(bstrTmp.asOutParam()); H();
640 InsertConfigString(pCfg, "VmUuid", bstrTmp);
641 }
642#endif
643
644#if defined(RT_OS_WINDOWS) || defined(RT_OS_LINUX)
645 if ( strcmp(pszDrvName, "HostAudioWas") == 0
646 || strcmp(pszDrvName, "PulseAudio") == 0)
647 {
648 Bstr bstrTmp;
649 HRESULT hrc = pMachine->COMGETTER(Name)(bstrTmp.asOutParam()); H();
650 InsertConfigString(pCfg, "VmName", bstrTmp);
651 }
652
653 /* Disabling caching code only is available for the HostAudioWas backend. */
654 if (strcmp(pszDrvName, "HostAudioWas") == 0)
655 {
656 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/Audio/CacheEnabled", &strTmp); /* Since VBox > 7.1.16. */
657 if (strTmp.isNotEmpty()) /* If value is not found, just skip. */
658 {
659 uint64_t const fCacheEnabled = strTmp.equalsIgnoreCase("true") || strTmp.equalsIgnoreCase("1");
660 InsertConfigInteger(pCfg, "CacheEnabled", fCacheEnabled);
661 }
662 }
663#endif
664
665 LogFlowFunc(("szDrivName=%s\n", pszDrvName));
666
667#undef H
668}
669
670/**
671 * Applies the CFGM overlay as specified by VBoxInternal/XXX extra data
672 * values.
673 *
674 * @returns VBox status code.
675 * @param pRoot The root of the configuration tree.
676 * @param pVirtualBox Pointer to the IVirtualBox interface.
677 * @param pMachine Pointer to the IMachine interface.
678 */
679/* static */
680int Console::i_configCfgmOverlay(PCFGMNODE pRoot, IVirtualBox *pVirtualBox, IMachine *pMachine)
681{
682 /*
683 * CFGM overlay handling.
684 *
685 * Here we check the extra data entries for CFGM values
686 * and create the nodes and insert the values on the fly. Existing
687 * values will be removed and reinserted. CFGM is typed, so by default
688 * we will guess whether it's a string or an integer (byte arrays are
689 * not currently supported). It's possible to override this autodetection
690 * by adding "string:", "integer:" or "bytes:" (future).
691 *
692 * We first perform a run on global extra data, then on the machine
693 * extra data to support global settings with local overrides.
694 */
695 int vrc = VINF_SUCCESS;
696 bool fFirst = true;
697 try
698 {
699 /** @todo add support for removing nodes and byte blobs. */
700 /*
701 * Get the next key
702 */
703 SafeArray<BSTR> aGlobalExtraDataKeys;
704 SafeArray<BSTR> aMachineExtraDataKeys;
705 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
706 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
707
708 // remember the no. of global values so we can call the correct method below
709 size_t cGlobalValues = aGlobalExtraDataKeys.size();
710
711 hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
712 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
713
714 // build a combined list from global keys...
715 std::list<Utf8Str> llExtraDataKeys;
716
717 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); ++i)
718 llExtraDataKeys.push_back(Utf8Str(aGlobalExtraDataKeys[i]));
719 // ... and machine keys
720 for (size_t i = 0; i < aMachineExtraDataKeys.size(); ++i)
721 llExtraDataKeys.push_back(Utf8Str(aMachineExtraDataKeys[i]));
722
723 size_t i2 = 0;
724 for (std::list<Utf8Str>::const_iterator it = llExtraDataKeys.begin();
725 it != llExtraDataKeys.end();
726 ++it, ++i2)
727 {
728 const Utf8Str &strKey = *it;
729
730 /*
731 * We only care about keys starting with "VBoxInternal/" (skip "G:" or "M:")
732 */
733 if (!strKey.startsWith("VBoxInternal/"))
734 continue;
735
736 const char *pszExtraDataKey = strKey.c_str() + sizeof("VBoxInternal/") - 1;
737
738 // get the value
739 Bstr bstrExtraDataValue;
740 if (i2 < cGlobalValues)
741 // this is still one of the global values:
742 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(), bstrExtraDataValue.asOutParam());
743 else
744 hrc = pMachine->GetExtraData(Bstr(strKey).raw(), bstrExtraDataValue.asOutParam());
745 if (FAILED(hrc))
746 LogRel(("Warning: Cannot get extra data key %s, hrc = %Rhrc\n", strKey.c_str(), hrc));
747
748 if (fFirst)
749 {
750 fFirst = false;
751 LogRel(("Extradata overrides:\n"));
752 }
753 LogRel((" %s=\"%ls\"%s\n", strKey.c_str(), bstrExtraDataValue.raw(), i2 < cGlobalValues ? " (global)" : ""));
754
755 /*
756 * The key will be in the format "Node1/Node2/Value" or simply "Value".
757 * Split the two and get the node, delete the value and create the node
758 * if necessary.
759 */
760 PCFGMNODE pNode;
761 const char *pszCFGMValueName = strrchr(pszExtraDataKey, '/');
762 if (pszCFGMValueName)
763 {
764 /* terminate the node and advance to the value (Utf8Str might not
765 offically like this but wtf) */
766 *(char *)pszCFGMValueName = '\0';
767 ++pszCFGMValueName;
768
769 /* does the node already exist? */
770 pNode = mpVMM->pfnCFGMR3GetChild(pRoot, pszExtraDataKey);
771 if (pNode)
772 mpVMM->pfnCFGMR3RemoveValue(pNode, pszCFGMValueName);
773 else
774 {
775 /* create the node */
776 vrc = mpVMM->pfnCFGMR3InsertNode(pRoot, pszExtraDataKey, &pNode);
777 if (RT_FAILURE(vrc))
778 {
779 AssertLogRelMsgRC(vrc, ("failed to insert node '%s'\n", pszExtraDataKey));
780 continue;
781 }
782 Assert(pNode);
783 }
784 }
785 else
786 {
787 /* root value (no node path). */
788 pNode = pRoot;
789 pszCFGMValueName = pszExtraDataKey;
790 pszExtraDataKey--;
791 mpVMM->pfnCFGMR3RemoveValue(pNode, pszCFGMValueName);
792 }
793
794 /*
795 * Now let's have a look at the value.
796 * Empty strings means that we should remove the value, which we've
797 * already done above.
798 */
799 Utf8Str strCFGMValueUtf8(bstrExtraDataValue);
800 if (strCFGMValueUtf8.isNotEmpty())
801 {
802 uint64_t u64Value;
803
804 /* check for type prefix first. */
805 if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("string:")))
806 vrc = mpVMM->pfnCFGMR3InsertString(pNode, pszCFGMValueName, strCFGMValueUtf8.c_str() + sizeof("string:") - 1);
807 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("integer:")))
808 {
809 vrc = RTStrToUInt64Full(strCFGMValueUtf8.c_str() + sizeof("integer:") - 1, 0, &u64Value);
810 if (RT_SUCCESS(vrc))
811 vrc = mpVMM->pfnCFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
812 }
813 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("bytes:")))
814 {
815 char const *pszBase64 = strCFGMValueUtf8.c_str() + sizeof("bytes:") - 1;
816 ssize_t cbValue = RTBase64DecodedSize(pszBase64, NULL);
817 if (cbValue > 0)
818 {
819 void *pvBytes = RTMemTmpAlloc(cbValue);
820 if (pvBytes)
821 {
822 vrc = RTBase64Decode(pszBase64, pvBytes, cbValue, NULL, NULL);
823 if (RT_SUCCESS(vrc))
824 vrc = mpVMM->pfnCFGMR3InsertBytes(pNode, pszCFGMValueName, pvBytes, cbValue);
825 RTMemTmpFree(pvBytes);
826 }
827 else
828 vrc = VERR_NO_TMP_MEMORY;
829 }
830 else if (cbValue == 0)
831 vrc = mpVMM->pfnCFGMR3InsertBytes(pNode, pszCFGMValueName, NULL, 0);
832 else
833 vrc = VERR_INVALID_BASE64_ENCODING;
834 }
835 /* auto detect type. */
836 else if (RT_SUCCESS(RTStrToUInt64Full(strCFGMValueUtf8.c_str(), 0, &u64Value)))
837 vrc = mpVMM->pfnCFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
838 else
839 vrc = mpVMM->pfnCFGMR3InsertString(pNode, pszCFGMValueName, strCFGMValueUtf8.c_str());
840 AssertLogRelMsgRCBreak(vrc, ("failed to insert CFGM value '%s' to key '%s'\n",
841 strCFGMValueUtf8.c_str(), pszExtraDataKey));
842 }
843 }
844 }
845 catch (ConfigError &x)
846 {
847 // InsertConfig threw something:
848 return x.m_vrc;
849 }
850 return vrc;
851}
852
853/**
854 * Dumps the API settings tweaks as specified by VBoxInternal2/XXX extra data
855 * values.
856 *
857 * @returns VBox status code.
858 * @param pVirtualBox Pointer to the IVirtualBox interface.
859 * @param pMachine Pointer to the IMachine interface.
860 */
861/* static */
862int Console::i_configDumpAPISettingsTweaks(IVirtualBox *pVirtualBox, IMachine *pMachine)
863{
864 {
865 SafeArray<BSTR> aGlobalExtraDataKeys;
866 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
867 if (SUCCEEDED(hrc))
868 {
869 bool hasKey = false;
870 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); i++)
871 {
872 Utf8Str strKey(aGlobalExtraDataKeys[i]);
873 if (!strKey.startsWith("VBoxInternal2/"))
874 continue;
875
876 Bstr bstrValue;
877 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(), bstrValue.asOutParam());
878 if (FAILED(hrc))
879 continue;
880 if (!hasKey)
881 LogRel(("Global extradata API settings:\n"));
882 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
883 hasKey = true;
884 }
885 }
886 else
887 AssertMsgFailed(("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
888 }
889
890 {
891 SafeArray<BSTR> aMachineExtraDataKeys;
892 HRESULT hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
893 if (SUCCEEDED(hrc))
894 {
895 bool hasKey = false;
896 for (size_t i = 0; i < aMachineExtraDataKeys.size(); i++)
897 {
898 Utf8Str strKey(aMachineExtraDataKeys[i]);
899 if (!strKey.startsWith("VBoxInternal2/"))
900 continue;
901
902 Bstr bstrValue;
903 hrc = pMachine->GetExtraData(Bstr(strKey).raw(), bstrValue.asOutParam());
904 if (FAILED(hrc))
905 continue;
906 if (!hasKey)
907 LogRel(("Per-VM extradata API settings:\n"));
908 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
909 hasKey = true;
910 }
911 }
912 else
913 AssertMsgFailed(("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
914 }
915
916 return VINF_SUCCESS;
917}
918
919
920/**
921 * Ellipsis to va_list wrapper for calling setVMRuntimeErrorCallback.
922 */
923void Console::i_atVMRuntimeErrorCallbackF(uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)
924{
925 va_list va;
926 va_start(va, pszFormat);
927 i_atVMRuntimeErrorCallback(NULL, this, fFlags, pszErrorId, pszFormat, va);
928 va_end(va);
929}
930
931/* XXX introduce RT format specifier */
932static uint64_t formatDiskSize(uint64_t u64Size, const char **pszUnit)
933{
934 if (u64Size > INT64_C(5000)*_1G)
935 {
936 *pszUnit = "TB";
937 return u64Size / _1T;
938 }
939 else if (u64Size > INT64_C(5000)*_1M)
940 {
941 *pszUnit = "GB";
942 return u64Size / _1G;
943 }
944 else
945 {
946 *pszUnit = "MB";
947 return u64Size / _1M;
948 }
949}
950
951/**
952 * Checks the location of the given medium for known bugs affecting the usage
953 * of the host I/O cache setting.
954 *
955 * @returns VBox status code.
956 * @param pMedium The medium to check.
957 * @param pfUseHostIOCache Where to store the suggested host I/O cache setting.
958 */
959int Console::i_checkMediumLocation(IMedium *pMedium, bool *pfUseHostIOCache)
960{
961#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
962 /*
963 * Some sanity checks.
964 */
965 RT_NOREF(pfUseHostIOCache);
966 ComPtr<IMediumFormat> pMediumFormat;
967 HRESULT hrc = pMedium->COMGETTER(MediumFormat)(pMediumFormat.asOutParam()); H();
968 ULONG uCaps = 0;
969 com::SafeArray <MediumFormatCapabilities_T> mediumFormatCap;
970 hrc = pMediumFormat->COMGETTER(Capabilities)(ComSafeArrayAsOutParam(mediumFormatCap)); H();
971
972 for (ULONG j = 0; j < mediumFormatCap.size(); j++)
973 uCaps |= mediumFormatCap[j];
974
975 if (uCaps & MediumFormatCapabilities_File)
976 {
977 Bstr bstrFile;
978 hrc = pMedium->COMGETTER(Location)(bstrFile.asOutParam()); H();
979 Utf8Str const strFile(bstrFile);
980
981 Bstr bstrSnap;
982 ComPtr<IMachine> pMachine = i_machine();
983 hrc = pMachine->COMGETTER(SnapshotFolder)(bstrSnap.asOutParam()); H();
984 Utf8Str const strSnap(bstrSnap);
985
986 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
987 int vrc2 = RTFsQueryType(strFile.c_str(), &enmFsTypeFile);
988 AssertMsgRCReturn(vrc2, ("Querying the file type of '%s' failed!\n", strFile.c_str()), vrc2);
989
990 /* Any VM which hasn't created a snapshot or saved the current state of the VM
991 * won't have a Snapshot folder yet so no need to log anything about the file system
992 * type of the non-existent directory in such cases. */
993 RTFSTYPE enmFsTypeSnap = RTFSTYPE_UNKNOWN;
994 vrc2 = RTFsQueryType(strSnap.c_str(), &enmFsTypeSnap);
995 if (RT_SUCCESS(vrc2) && !mfSnapshotFolderDiskTypeShown)
996 {
997 LogRel(("File system of '%s' (snapshots) is %s\n", strSnap.c_str(), RTFsTypeName(enmFsTypeSnap)));
998 mfSnapshotFolderDiskTypeShown = true;
999 }
1000 LogRel(("File system of '%s' is %s\n", strFile.c_str(), RTFsTypeName(enmFsTypeFile)));
1001 LONG64 i64Size;
1002 hrc = pMedium->COMGETTER(LogicalSize)(&i64Size); H();
1003#ifdef RT_OS_WINDOWS
1004 if ( enmFsTypeFile == RTFSTYPE_FAT
1005 && i64Size >= _4G)
1006 {
1007 const char *pszUnit;
1008 uint64_t u64Print = formatDiskSize((uint64_t)i64Size, &pszUnit);
1009 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
1010 N_("The medium '%s' has a logical size of %RU64%s "
1011 "but the file system the medium is located on seems "
1012 "to be FAT(32) which cannot handle files bigger than 4GB.\n"
1013 "We strongly recommend to put all your virtual disk images and "
1014 "the snapshot folder onto an NTFS partition"),
1015 strFile.c_str(), u64Print, pszUnit);
1016 }
1017#else /* !RT_OS_WINDOWS */
1018 if ( enmFsTypeFile == RTFSTYPE_FAT
1019 || enmFsTypeFile == RTFSTYPE_EXT
1020 || enmFsTypeFile == RTFSTYPE_EXT2
1021 || enmFsTypeFile == RTFSTYPE_EXT3
1022 || enmFsTypeFile == RTFSTYPE_EXT4)
1023 {
1024 RTFILE file;
1025 int vrc = RTFileOpen(&file, strFile.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
1026 if (RT_SUCCESS(vrc))
1027 {
1028 RTFOFF maxSize;
1029 /* Careful: This function will work only on selected local file systems! */
1030 vrc = RTFileQueryMaxSizeEx(file, &maxSize);
1031 RTFileClose(file);
1032 if ( RT_SUCCESS(vrc)
1033 && maxSize > 0
1034 && i64Size > (LONG64)maxSize)
1035 {
1036 const char *pszUnitSiz;
1037 const char *pszUnitMax;
1038 uint64_t u64PrintSiz = formatDiskSize((LONG64)i64Size, &pszUnitSiz);
1039 uint64_t u64PrintMax = formatDiskSize(maxSize, &pszUnitMax);
1040 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected", /* <= not exact but ... */
1041 N_("The medium '%s' has a logical size of %RU64%s "
1042 "but the file system the medium is located on can "
1043 "only handle files up to %RU64%s in theory.\n"
1044 "We strongly recommend to put all your virtual disk "
1045 "images and the snapshot folder onto a proper "
1046 "file system (e.g. ext3) with a sufficient size"),
1047 strFile.c_str(), u64PrintSiz, pszUnitSiz, u64PrintMax, pszUnitMax);
1048 }
1049 }
1050 }
1051#endif /* !RT_OS_WINDOWS */
1052
1053 /*
1054 * Snapshot folder:
1055 * Here we test only for a FAT partition as we had to create a dummy file otherwise
1056 */
1057 if ( enmFsTypeSnap == RTFSTYPE_FAT
1058 && i64Size >= _4G
1059 && !mfSnapshotFolderSizeWarningShown)
1060 {
1061 const char *pszUnit;
1062 uint64_t u64Print = formatDiskSize(i64Size, &pszUnit);
1063 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
1064#ifdef RT_OS_WINDOWS
1065 N_("The snapshot folder of this VM '%s' seems to be located on "
1066 "a FAT(32) file system. The logical size of the medium '%s' "
1067 "(%RU64%s) is bigger than the maximum file size this file "
1068 "system can handle (4GB).\n"
1069 "We strongly recommend to put all your virtual disk images and "
1070 "the snapshot folder onto an NTFS partition"),
1071#else
1072 N_("The snapshot folder of this VM '%s' seems to be located on "
1073 "a FAT(32) file system. The logical size of the medium '%s' "
1074 "(%RU64%s) is bigger than the maximum file size this file "
1075 "system can handle (4GB).\n"
1076 "We strongly recommend to put all your virtual disk images and "
1077 "the snapshot folder onto a proper file system (e.g. ext3)"),
1078#endif
1079 strSnap.c_str(), strFile.c_str(), u64Print, pszUnit);
1080 /* Show this particular warning only once */
1081 mfSnapshotFolderSizeWarningShown = true;
1082 }
1083
1084#ifdef RT_OS_LINUX
1085 /*
1086 * Ext4 bug: Check if the host I/O cache is disabled and the disk image is located
1087 * on an ext4 partition.
1088 * This bug apparently applies to the XFS file system as well.
1089 * Linux 2.6.36 is known to be fixed (tested with 2.6.36-rc4).
1090 */
1091
1092 char szOsRelease[128];
1093 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOsRelease, sizeof(szOsRelease));
1094 bool fKernelHasODirectBug = RT_FAILURE(vrc)
1095 || (RTStrVersionCompare(szOsRelease, "2.6.36-rc4") < 0);
1096
1097 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
1098 && !*pfUseHostIOCache
1099 && fKernelHasODirectBug)
1100 {
1101 if ( enmFsTypeFile == RTFSTYPE_EXT4
1102 || enmFsTypeFile == RTFSTYPE_XFS)
1103 {
1104 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
1105 N_("The host I/O cache for at least one controller is disabled "
1106 "and the medium '%s' for this VM "
1107 "is located on an %s partition. There is a known Linux "
1108 "kernel bug which can lead to the corruption of the virtual "
1109 "disk image under these conditions.\n"
1110 "Either enable the host I/O cache permanently in the VM "
1111 "settings or put the disk image and the snapshot folder "
1112 "onto a different file system.\n"
1113 "The host I/O cache will now be enabled for this medium"),
1114 strFile.c_str(), enmFsTypeFile == RTFSTYPE_EXT4 ? "ext4" : "xfs");
1115 *pfUseHostIOCache = true;
1116 }
1117 else if ( ( enmFsTypeSnap == RTFSTYPE_EXT4
1118 || enmFsTypeSnap == RTFSTYPE_XFS)
1119 && !mfSnapshotFolderExt4WarningShown)
1120 {
1121 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
1122 N_("The host I/O cache for at least one controller is disabled "
1123 "and the snapshot folder for this VM "
1124 "is located on an %s partition. There is a known Linux "
1125 "kernel bug which can lead to the corruption of the virtual "
1126 "disk image under these conditions.\n"
1127 "Either enable the host I/O cache permanently in the VM "
1128 "settings or put the disk image and the snapshot folder "
1129 "onto a different file system.\n"
1130 "The host I/O cache will now be enabled for this medium"),
1131 enmFsTypeSnap == RTFSTYPE_EXT4 ? "ext4" : "xfs");
1132 *pfUseHostIOCache = true;
1133 mfSnapshotFolderExt4WarningShown = true;
1134 }
1135 }
1136
1137 /*
1138 * 2.6.18 bug: Check if the host I/O cache is disabled and the host is running
1139 * Linux 2.6.18. See @bugref{8690}. Apparently the same problem as
1140 * documented in https://lkml.org/lkml/2007/2/1/14. We saw such
1141 * kernel oopses on Linux 2.6.18-416.el5. We don't know when this
1142 * was fixed but we _know_ that 2.6.18 EL5 kernels are affected.
1143 */
1144 bool fKernelAsyncUnreliable = RT_FAILURE(vrc)
1145 || (RTStrVersionCompare(szOsRelease, "2.6.19") < 0);
1146 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
1147 && !*pfUseHostIOCache
1148 && fKernelAsyncUnreliable)
1149 {
1150 i_atVMRuntimeErrorCallbackF(0, "Linux2618TooOld",
1151 N_("The host I/O cache for at least one controller is disabled. "
1152 "There is a known Linux kernel bug which can lead to kernel "
1153 "oopses under heavy load. To our knowledge this bug affects "
1154 "all 2.6.18 kernels.\n"
1155 "Either enable the host I/O cache permanently in the VM "
1156 "settings or switch to a newer host kernel.\n"
1157 "The host I/O cache will now be enabled for this medium"));
1158 *pfUseHostIOCache = true;
1159 }
1160#endif
1161 }
1162#undef H
1163
1164 return VINF_SUCCESS;
1165}
1166
1167/**
1168 * Unmounts the specified medium from the specified device.
1169 *
1170 * @returns VBox status code.
1171 * @param pUVM The usermode VM handle.
1172 * @param pVMM The VMM vtable.
1173 * @param enmBus The storage bus.
1174 * @param enmDevType The device type.
1175 * @param pcszDevice The device emulation.
1176 * @param uInstance Instance of the device.
1177 * @param uLUN The LUN on the device.
1178 * @param fForceUnmount Whether to force unmounting.
1179 */
1180int Console::i_unmountMediumFromGuest(PUVM pUVM, PCVMMR3VTABLE pVMM, StorageBus_T enmBus, DeviceType_T enmDevType,
1181 const char *pcszDevice, unsigned uInstance, unsigned uLUN,
1182 bool fForceUnmount) RT_NOEXCEPT
1183{
1184 /* Unmount existing media only for floppy and DVD drives. */
1185 int vrc = VINF_SUCCESS;
1186 PPDMIBASE pBase;
1187 if (enmBus == StorageBus_USB)
1188 vrc = pVMM->pfnPDMR3UsbQueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
1189 else if ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI || enmBus == StorageBus_VirtioSCSI)
1190 || (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD))
1191 vrc = pVMM->pfnPDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
1192 else /* IDE or Floppy */
1193 vrc = pVMM->pfnPDMR3QueryLun(pUVM, pcszDevice, uInstance, uLUN, &pBase);
1194
1195 if (RT_FAILURE(vrc))
1196 {
1197 if (vrc == VERR_PDM_LUN_NOT_FOUND || vrc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
1198 vrc = VINF_SUCCESS;
1199 AssertRC(vrc);
1200 }
1201 else
1202 {
1203 PPDMIMOUNT pIMount = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMOUNT);
1204 AssertPtrReturn(pIMount, VERR_INVALID_POINTER);
1205
1206 /* Unmount the media (but do not eject the medium!) */
1207 vrc = pIMount->pfnUnmount(pIMount, fForceUnmount, false /*=fEject*/);
1208 if (vrc == VERR_PDM_MEDIA_NOT_MOUNTED)
1209 vrc = VINF_SUCCESS;
1210 /* for example if the medium is locked */
1211 else if (RT_FAILURE(vrc))
1212 return vrc;
1213 }
1214
1215 return vrc;
1216}
1217
1218/**
1219 * Removes the currently attached medium driver form the specified device
1220 * taking care of the controlelr specific configs wrt. to the attached driver chain.
1221 *
1222 * @returns VBox status code.
1223 * @param pCtlInst The controler instance node in the CFGM tree.
1224 * @param pcszDevice The device name.
1225 * @param uInstance The device instance.
1226 * @param uLUN The device LUN.
1227 * @param enmBus The storage bus.
1228 * @param fAttachDetach Flag whether this is a change while the VM is running
1229 * @param fHotplug Flag whether the guest should be notified about the device change.
1230 * @param fForceUnmount Flag whether to force unmounting the medium even if it is locked.
1231 * @param pUVM The usermode VM handle.
1232 * @param pVMM The VMM vtable.
1233 * @param enmDevType The device type.
1234 * @param ppLunL0 Where to store the node to attach the new config to on success.
1235 */
1236int Console::i_removeMediumDriverFromVm(PCFGMNODE pCtlInst,
1237 const char *pcszDevice,
1238 unsigned uInstance,
1239 unsigned uLUN,
1240 StorageBus_T enmBus,
1241 bool fAttachDetach,
1242 bool fHotplug,
1243 bool fForceUnmount,
1244 PUVM pUVM,
1245 PCVMMR3VTABLE pVMM,
1246 DeviceType_T enmDevType,
1247 PCFGMNODE *ppLunL0)
1248{
1249 int vrc = VINF_SUCCESS;
1250 bool fAddLun = false;
1251
1252 /* First check if the LUN already exists. */
1253 PCFGMNODE pLunL0 = pVMM->pfnCFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
1254 AssertReturn(!RT_VALID_PTR(pLunL0) || fAttachDetach, VERR_INTERNAL_ERROR);
1255
1256 if (pLunL0)
1257 {
1258 /*
1259 * Unmount the currently mounted medium if we don't just hot remove the
1260 * complete device (SATA) and it supports unmounting (DVD).
1261 */
1262 if ( (enmDevType != DeviceType_HardDisk)
1263 && !fHotplug)
1264 {
1265 vrc = i_unmountMediumFromGuest(pUVM, pVMM, enmBus, enmDevType, pcszDevice, uInstance, uLUN, fForceUnmount);
1266 if (RT_FAILURE(vrc))
1267 return vrc;
1268 }
1269
1270 /*
1271 * Don't detach the SCSI driver when unmounting the current medium
1272 * (we are not ripping out the device but only eject the medium).
1273 */
1274 char *pszDriverDetach = NULL;
1275 if ( !fHotplug
1276 && ( (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD)
1277 || enmBus == StorageBus_SAS
1278 || enmBus == StorageBus_SCSI
1279 || enmBus == StorageBus_VirtioSCSI
1280 || enmBus == StorageBus_USB))
1281 {
1282 /* Get the current attached driver we have to detach. */
1283 PCFGMNODE pDrvLun = pVMM->pfnCFGMR3GetChildF(pCtlInst, "LUN#%u/AttachedDriver/", uLUN);
1284 if (pDrvLun)
1285 {
1286 char szDriver[128];
1287 RT_ZERO(szDriver);
1288 vrc = pVMM->pfnCFGMR3QueryString(pDrvLun, "Driver", &szDriver[0], sizeof(szDriver));
1289 if (RT_SUCCESS(vrc))
1290 pszDriverDetach = RTStrDup(&szDriver[0]);
1291
1292 pLunL0 = pDrvLun;
1293 }
1294 }
1295
1296 if (enmBus == StorageBus_USB)
1297 vrc = pVMM->pfnPDMR3UsbDriverDetach(pUVM, pcszDevice, uInstance, uLUN, pszDriverDetach,
1298 0 /* iOccurence */, fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
1299 else
1300 vrc = pVMM->pfnPDMR3DriverDetach(pUVM, pcszDevice, uInstance, uLUN, pszDriverDetach,
1301 0 /* iOccurence */, fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
1302
1303 if (pszDriverDetach)
1304 {
1305 RTStrFree(pszDriverDetach);
1306 /* Remove the complete node and create new for the new config. */
1307 pVMM->pfnCFGMR3RemoveNode(pLunL0);
1308 pLunL0 = pVMM->pfnCFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
1309 if (pLunL0)
1310 {
1311 try
1312 {
1313 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
1314 }
1315 catch (ConfigError &x)
1316 {
1317 // InsertConfig threw something:
1318 return x.m_vrc;
1319 }
1320 }
1321 }
1322 if (vrc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
1323 vrc = VINF_SUCCESS;
1324 AssertRCReturn(vrc, vrc);
1325
1326 /*
1327 * Don't remove the LUN except for IDE/floppy/NVMe (which connects directly to the medium driver
1328 * even for DVD devices) or if there is a hotplug event which rips out the complete device.
1329 */
1330 if ( fHotplug
1331 || enmBus == StorageBus_IDE
1332 || enmBus == StorageBus_Floppy
1333 || enmBus == StorageBus_PCIe
1334 || (enmBus == StorageBus_SATA && enmDevType != DeviceType_DVD))
1335 {
1336 fAddLun = true;
1337 pVMM->pfnCFGMR3RemoveNode(pLunL0);
1338 }
1339 }
1340 else
1341 fAddLun = true;
1342
1343 try
1344 {
1345 if (fAddLun)
1346 InsertConfigNodeF(pCtlInst, &pLunL0, "LUN#%u", uLUN);
1347 }
1348 catch (ConfigError &x)
1349 {
1350 // InsertConfig threw something:
1351 return x.m_vrc;
1352 }
1353
1354 if (ppLunL0)
1355 *ppLunL0 = pLunL0;
1356
1357 return vrc;
1358}
1359
1360int Console::i_configMediumAttachment(const char *pcszDevice,
1361 unsigned uInstance,
1362 StorageBus_T enmBus,
1363 bool fUseHostIOCache,
1364 bool fBuiltinIOCache,
1365 bool fInsertDiskIntegrityDrv,
1366 bool fSetupMerge,
1367 unsigned uMergeSource,
1368 unsigned uMergeTarget,
1369 IMediumAttachment *pMediumAtt,
1370 MachineState_T aMachineState,
1371 HRESULT *phrc,
1372 bool fAttachDetach,
1373 bool fForceUnmount,
1374 bool fHotplug,
1375 PUVM pUVM,
1376 PCVMMR3VTABLE pVMM,
1377 DeviceType_T *paLedDevType,
1378 PCFGMNODE *ppLunL0)
1379{
1380 // InsertConfig* throws
1381 try
1382 {
1383 int vrc = VINF_SUCCESS;
1384 HRESULT hrc;
1385 Bstr bstr;
1386 PCFGMNODE pCtlInst = NULL;
1387
1388// #define RC_CHECK() AssertMsgReturn(RT_SUCCESS(vrc), ("vrc=%Rrc\n", vrc), vrc)
1389#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
1390
1391 LONG lDev;
1392 hrc = pMediumAtt->COMGETTER(Device)(&lDev); H();
1393 LONG lPort;
1394 hrc = pMediumAtt->COMGETTER(Port)(&lPort); H();
1395 DeviceType_T enmType;
1396 hrc = pMediumAtt->COMGETTER(Type)(&enmType); H();
1397 BOOL fNonRotational;
1398 hrc = pMediumAtt->COMGETTER(NonRotational)(&fNonRotational); H();
1399 BOOL fDiscard;
1400 hrc = pMediumAtt->COMGETTER(Discard)(&fDiscard); H();
1401
1402 if (enmType == DeviceType_DVD)
1403 fInsertDiskIntegrityDrv = false;
1404
1405 unsigned uLUN;
1406 PCFGMNODE pLunL0 = NULL;
1407 hrc = Console::i_storageBusPortDeviceToLun(enmBus, lPort, lDev, uLUN); H();
1408
1409 /* Determine the base path for the device instance. */
1410 if (enmBus != StorageBus_USB)
1411 pCtlInst = pVMM->pfnCFGMR3GetChildF(pVMM->pfnCFGMR3GetRootU(pUVM), "Devices/%s/%u/", pcszDevice, uInstance);
1412 else
1413 {
1414 /* If we hotplug a USB device create a new CFGM tree. */
1415 if (!fHotplug)
1416 pCtlInst = pVMM->pfnCFGMR3GetChildF(pVMM->pfnCFGMR3GetRootU(pUVM), "USB/%s/", pcszDevice);
1417 else
1418 pCtlInst = pVMM->pfnCFGMR3CreateTree(pUVM); /** @todo r=bird: Leaked in error paths! */
1419 }
1420 AssertReturn(pCtlInst, VERR_INTERNAL_ERROR);
1421
1422 if (enmBus == StorageBus_USB)
1423 {
1424 PCFGMNODE pCfg = NULL;
1425
1426 /* Create correct instance. */
1427 if (!fHotplug)
1428 {
1429 if (!fAttachDetach)
1430 InsertConfigNodeF(pCtlInst, &pCtlInst, "%d", lPort);
1431 else
1432 pCtlInst = pVMM->pfnCFGMR3GetChildF(pCtlInst, "%d/", lPort);
1433 }
1434
1435 if (!fAttachDetach)
1436 InsertConfigNode(pCtlInst, "Config", &pCfg);
1437
1438 uInstance = lPort; /* Overwrite uInstance with the correct one. */
1439
1440 /** @todo No LED after hotplugging. */
1441 if (!fHotplug && !fAttachDetach)
1442 {
1443 USBStorageDevice UsbMsd;
1444 UsbMsd.iPort = uInstance;
1445 vrc = RTUuidCreate(&UsbMsd.mUuid);
1446 AssertRCReturn(vrc, vrc);
1447
1448 InsertConfigStringF(pCtlInst, "UUID", "%RTuuid", &UsbMsd.mUuid);
1449
1450 mUSBStorageDevices.push_back(UsbMsd);
1451
1452 /** @todo This LED set is not freed if the device is unplugged. We could
1453 * keep the LED set index in the UsbMsd structure and clean it up in
1454 * i_detachStorageDevice. */
1455 /* Attach the status driver */
1456 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk),
1457 8, &paLedDevType, &mapMediumAttachments, pcszDevice, 0);
1458 }
1459 }
1460
1461 vrc = i_removeMediumDriverFromVm(pCtlInst, pcszDevice, uInstance, uLUN, enmBus, fAttachDetach,
1462 fHotplug, fForceUnmount, pUVM, pVMM, enmType, &pLunL0);
1463 if (RT_FAILURE(vrc))
1464 return vrc;
1465 if (ppLunL0)
1466 *ppLunL0 = pLunL0;
1467
1468 Utf8StrFmt devicePath("%s/%u/LUN#%u", pcszDevice, uInstance, uLUN);
1469 mapMediumAttachments[devicePath] = pMediumAtt;
1470
1471 ComPtr<IMedium> ptrMedium;
1472 hrc = pMediumAtt->COMGETTER(Medium)(ptrMedium.asOutParam()); H();
1473
1474 /*
1475 * 1. Only check this for hard disk images.
1476 * 2. Only check during VM creation and not later, especially not during
1477 * taking an online snapshot!
1478 */
1479 if ( enmType == DeviceType_HardDisk
1480 && ( aMachineState == MachineState_Starting
1481 || aMachineState == MachineState_Restoring))
1482 {
1483 vrc = i_checkMediumLocation(ptrMedium, &fUseHostIOCache);
1484 if (RT_FAILURE(vrc))
1485 return vrc;
1486 }
1487
1488 BOOL fPassthrough = FALSE;
1489 if (ptrMedium.isNotNull())
1490 {
1491 BOOL fHostDrive;
1492 hrc = ptrMedium->COMGETTER(HostDrive)(&fHostDrive); H();
1493 if ( ( enmType == DeviceType_DVD
1494 || enmType == DeviceType_Floppy)
1495 && !fHostDrive)
1496 {
1497 /*
1498 * Informative logging.
1499 */
1500 Bstr bstrFile;
1501 hrc = ptrMedium->COMGETTER(Location)(bstrFile.asOutParam()); H();
1502 Utf8Str strFile(bstrFile);
1503 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
1504 (void)RTFsQueryType(strFile.c_str(), &enmFsTypeFile);
1505 LogRel(("File system of '%s' (%s) is %s\n",
1506 strFile.c_str(), enmType == DeviceType_DVD ? "DVD" : "Floppy", RTFsTypeName(enmFsTypeFile)));
1507 }
1508
1509 if (fHostDrive)
1510 {
1511 hrc = pMediumAtt->COMGETTER(Passthrough)(&fPassthrough); H();
1512 }
1513 }
1514
1515 ComObjPtr<IBandwidthGroup> pBwGroup;
1516 Bstr bstrBwGroup;
1517 hrc = pMediumAtt->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
1518
1519 if (!pBwGroup.isNull())
1520 {
1521 hrc = pBwGroup->COMGETTER(Name)(bstrBwGroup.asOutParam()); H();
1522 }
1523
1524 /*
1525 * Insert the SCSI driver for hotplug events on the SCSI/USB based storage controllers
1526 * or for SATA if the new device is a CD/DVD drive.
1527 */
1528 if ( (fHotplug || !fAttachDetach)
1529 && ( enmBus == StorageBus_SCSI
1530 || enmBus == StorageBus_SAS
1531 || enmBus == StorageBus_USB
1532 || enmBus == StorageBus_VirtioSCSI
1533 || (enmBus == StorageBus_SATA && enmType == DeviceType_DVD && !fPassthrough)))
1534 {
1535 InsertConfigString(pLunL0, "Driver", "SCSI");
1536 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
1537 }
1538
1539 vrc = i_configMedium(pLunL0,
1540 !!fPassthrough,
1541 enmType,
1542 fUseHostIOCache,
1543 fBuiltinIOCache,
1544 fInsertDiskIntegrityDrv,
1545 fSetupMerge,
1546 uMergeSource,
1547 uMergeTarget,
1548 bstrBwGroup.isEmpty() ? NULL : Utf8Str(bstrBwGroup).c_str(),
1549 !!fDiscard,
1550 !!fNonRotational,
1551 ptrMedium,
1552 aMachineState,
1553 phrc);
1554 if (RT_FAILURE(vrc))
1555 return vrc;
1556
1557 if (fAttachDetach)
1558 {
1559 /* Attach the new driver. */
1560 if (enmBus == StorageBus_USB)
1561 {
1562 if (fHotplug)
1563 {
1564 USBStorageDevice UsbMsd;
1565 RTUuidCreate(&UsbMsd.mUuid);
1566 UsbMsd.iPort = uInstance;
1567 vrc = pVMM->pfnPDMR3UsbCreateEmulatedDevice(pUVM, pcszDevice, pCtlInst, &UsbMsd.mUuid, NULL);
1568 if (RT_SUCCESS(vrc))
1569 mUSBStorageDevices.push_back(UsbMsd);
1570 }
1571 else
1572 vrc = pVMM->pfnPDMR3UsbDriverAttach(pUVM, pcszDevice, uInstance, uLUN,
1573 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
1574 }
1575 else if ( !fHotplug
1576 && ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI || enmBus == StorageBus_VirtioSCSI)
1577 || (enmBus == StorageBus_SATA && enmType == DeviceType_DVD)))
1578 vrc = pVMM->pfnPDMR3DriverAttach(pUVM, pcszDevice, uInstance, uLUN,
1579 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
1580 else
1581 vrc = pVMM->pfnPDMR3DeviceAttach(pUVM, pcszDevice, uInstance, uLUN,
1582 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
1583 AssertRCReturn(vrc, vrc);
1584
1585 /*
1586 * Make the secret key helper interface known to the VD driver if it is attached,
1587 * so we can get notified about missing keys.
1588 */
1589 PPDMIBASE pIBase = NULL;
1590 vrc = pVMM->pfnPDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "VD", &pIBase);
1591 if (RT_SUCCESS(vrc) && pIBase)
1592 {
1593 PPDMIMEDIA pIMedium = (PPDMIMEDIA)pIBase->pfnQueryInterface(pIBase, PDMIMEDIA_IID);
1594 if (pIMedium)
1595 {
1596 vrc = pIMedium->pfnSetSecKeyIf(pIMedium, mpIfSecKey, mpIfSecKeyHlp);
1597 Assert(RT_SUCCESS(vrc) || vrc == VERR_NOT_SUPPORTED);
1598 }
1599 }
1600
1601 /* There is no need to handle removable medium mounting, as we
1602 * unconditionally replace everthing including the block driver level.
1603 * This means the new medium will be picked up automatically. */
1604 }
1605
1606 if (paLedDevType)
1607 i_setLedType(&paLedDevType[uLUN], enmType);
1608
1609 /* Dump the changed LUN if possible, dump the complete device otherwise */
1610 if ( aMachineState != MachineState_Starting
1611 && aMachineState != MachineState_Restoring)
1612 pVMM->pfnCFGMR3Dump(pLunL0 ? pLunL0 : pCtlInst);
1613 }
1614 catch (ConfigError &x)
1615 {
1616 // InsertConfig threw something:
1617 return x.m_vrc;
1618 }
1619
1620#undef H
1621
1622 return VINF_SUCCESS;
1623}
1624
1625int Console::i_configMedium(PCFGMNODE pLunL0,
1626 bool fPassthrough,
1627 DeviceType_T enmType,
1628 bool fUseHostIOCache,
1629 bool fBuiltinIOCache,
1630 bool fInsertDiskIntegrityDrv,
1631 bool fSetupMerge,
1632 unsigned uMergeSource,
1633 unsigned uMergeTarget,
1634 const char *pcszBwGroup,
1635 bool fDiscard,
1636 bool fNonRotational,
1637 ComPtr<IMedium> ptrMedium,
1638 MachineState_T aMachineState,
1639 HRESULT *phrc)
1640{
1641 // InsertConfig* throws
1642 try
1643 {
1644 HRESULT hrc;
1645 Bstr bstr;
1646 PCFGMNODE pCfg = NULL;
1647
1648#define H() \
1649 AssertMsgReturnStmt(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), if (phrc) *phrc = hrc, Global::vboxStatusCodeFromCOM(hrc))
1650
1651
1652 BOOL fHostDrive = FALSE;
1653 MediumType_T mediumType = MediumType_Normal;
1654 if (ptrMedium.isNotNull())
1655 {
1656 hrc = ptrMedium->COMGETTER(HostDrive)(&fHostDrive); H();
1657 hrc = ptrMedium->COMGETTER(Type)(&mediumType); H();
1658 }
1659
1660 if (fHostDrive)
1661 {
1662 Assert(ptrMedium.isNotNull());
1663 if (enmType == DeviceType_DVD)
1664 {
1665 InsertConfigString(pLunL0, "Driver", "HostDVD");
1666 InsertConfigNode(pLunL0, "Config", &pCfg);
1667
1668 hrc = ptrMedium->COMGETTER(Location)(bstr.asOutParam()); H();
1669 InsertConfigString(pCfg, "Path", bstr);
1670
1671 InsertConfigInteger(pCfg, "Passthrough", fPassthrough);
1672 }
1673 else if (enmType == DeviceType_Floppy)
1674 {
1675 InsertConfigString(pLunL0, "Driver", "HostFloppy");
1676 InsertConfigNode(pLunL0, "Config", &pCfg);
1677
1678 hrc = ptrMedium->COMGETTER(Location)(bstr.asOutParam()); H();
1679 InsertConfigString(pCfg, "Path", bstr);
1680 }
1681 }
1682 else
1683 {
1684 if (fInsertDiskIntegrityDrv)
1685 {
1686 /*
1687 * The actual configuration is done through CFGM extra data
1688 * for each inserted driver separately.
1689 */
1690 InsertConfigString(pLunL0, "Driver", "DiskIntegrity");
1691 InsertConfigNode(pLunL0, "Config", &pCfg);
1692 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
1693 }
1694
1695 InsertConfigString(pLunL0, "Driver", "VD");
1696 InsertConfigNode(pLunL0, "Config", &pCfg);
1697 switch (enmType)
1698 {
1699 case DeviceType_DVD:
1700 InsertConfigString(pCfg, "Type", "DVD");
1701 InsertConfigInteger(pCfg, "Mountable", 1);
1702 break;
1703 case DeviceType_Floppy:
1704 InsertConfigString(pCfg, "Type", "Floppy 1.44");
1705 InsertConfigInteger(pCfg, "Mountable", 1);
1706 break;
1707 case DeviceType_HardDisk:
1708 default:
1709 InsertConfigString(pCfg, "Type", "HardDisk");
1710 InsertConfigInteger(pCfg, "Mountable", 0);
1711 }
1712
1713 if ( ptrMedium.isNotNull()
1714 && ( enmType == DeviceType_DVD
1715 || enmType == DeviceType_Floppy)
1716 )
1717 {
1718 // if this medium represents an ISO image and this image is inaccessible,
1719 // the ignore it instead of causing a failure; this can happen when we
1720 // restore a VM state and the ISO has disappeared, e.g. because the Guest
1721 // Additions were mounted and the user upgraded VirtualBox. Previously
1722 // we failed on startup, but that's not good because the only way out then
1723 // would be to discard the VM state...
1724 MediumState_T mediumState;
1725 hrc = ptrMedium->RefreshState(&mediumState); H();
1726 if (mediumState == MediumState_Inaccessible)
1727 {
1728 Bstr loc;
1729 hrc = ptrMedium->COMGETTER(Location)(loc.asOutParam()); H();
1730 i_atVMRuntimeErrorCallbackF(0, "DvdOrFloppyImageInaccessible",
1731 N_("The image file '%ls' is inaccessible and is being ignored. "
1732 "Please select a different image file for the virtual %s drive."),
1733 loc.raw(),
1734 enmType == DeviceType_DVD ? "DVD" : "floppy");
1735 ptrMedium.setNull();
1736 }
1737 }
1738
1739 if (ptrMedium.isNotNull())
1740 {
1741 /* Start with length of parent chain, as the list is reversed */
1742 unsigned uImage = 0;
1743 ComPtr<IMedium> ptrTmp = ptrMedium;
1744 while (ptrTmp.isNotNull())
1745 {
1746 uImage++;
1747 ComPtr<IMedium> ptrParent;
1748 hrc = ptrTmp->COMGETTER(Parent)(ptrParent.asOutParam()); H();
1749 ptrTmp = ptrParent;
1750 }
1751 /* Index of last image */
1752 uImage--;
1753
1754# ifdef VBOX_WITH_EXTPACK
1755 if (mptrExtPackManager->i_isExtPackUsable(ORACLE_PUEL_EXTPACK_NAME))
1756 {
1757 /* Configure loading the VDPlugin. */
1758 static const char s_szVDPlugin[] = "VDPluginCrypt";
1759 PCFGMNODE pCfgPlugins = NULL;
1760 PCFGMNODE pCfgPlugin = NULL;
1761 Utf8Str strPlugin;
1762 hrc = mptrExtPackManager->i_getLibraryPathForExtPack(s_szVDPlugin, ORACLE_PUEL_EXTPACK_NAME, &strPlugin);
1763 // Don't fail, this is optional!
1764 if (SUCCEEDED(hrc))
1765 {
1766 InsertConfigNode(pCfg, "Plugins", &pCfgPlugins);
1767 InsertConfigNode(pCfgPlugins, s_szVDPlugin, &pCfgPlugin);
1768 InsertConfigString(pCfgPlugin, "Path", strPlugin);
1769 }
1770 }
1771# endif
1772
1773 hrc = ptrMedium->COMGETTER(Location)(bstr.asOutParam()); H();
1774 InsertConfigString(pCfg, "Path", bstr);
1775
1776 hrc = ptrMedium->COMGETTER(Format)(bstr.asOutParam()); H();
1777 InsertConfigString(pCfg, "Format", bstr);
1778
1779 if (mediumType == MediumType_Readonly)
1780 InsertConfigInteger(pCfg, "ReadOnly", 1);
1781 else if (enmType == DeviceType_Floppy)
1782 InsertConfigInteger(pCfg, "MaybeReadOnly", 1);
1783
1784 /* Start without exclusive write access to the images. */
1785 /** @todo Live Migration: I don't quite like this, we risk screwing up when
1786 * we're resuming the VM if some 3rd dude have any of the VDIs open
1787 * with write sharing denied. However, if the two VMs are sharing a
1788 * image it really is necessary....
1789 *
1790 * So, on the "lock-media" command, the target teleporter should also
1791 * make DrvVD undo TempReadOnly. It gets interesting if we fail after
1792 * that. Grumble. */
1793 if ( enmType == DeviceType_HardDisk
1794 && aMachineState == MachineState_TeleportingIn)
1795 InsertConfigInteger(pCfg, "TempReadOnly", 1);
1796
1797 /* Flag for opening the medium for sharing between VMs. This
1798 * is done at the moment only for the first (and only) medium
1799 * in the chain, as shared media can have no diffs. */
1800 if (mediumType == MediumType_Shareable)
1801 InsertConfigInteger(pCfg, "Shareable", 1);
1802
1803 if (!fUseHostIOCache)
1804 {
1805 InsertConfigInteger(pCfg, "UseNewIo", 1);
1806 /*
1807 * Activate the builtin I/O cache for harddisks only.
1808 * It caches writes only which doesn't make sense for DVD drives
1809 * and just increases the overhead.
1810 */
1811 if ( fBuiltinIOCache
1812 && (enmType == DeviceType_HardDisk))
1813 InsertConfigInteger(pCfg, "BlockCache", 1);
1814 }
1815
1816 if (fSetupMerge)
1817 {
1818 InsertConfigInteger(pCfg, "SetupMerge", 1);
1819 if (uImage == uMergeSource)
1820 InsertConfigInteger(pCfg, "MergeSource", 1);
1821 else if (uImage == uMergeTarget)
1822 InsertConfigInteger(pCfg, "MergeTarget", 1);
1823 }
1824
1825 if (pcszBwGroup)
1826 InsertConfigString(pCfg, "BwGroup", pcszBwGroup);
1827
1828 if (fDiscard)
1829 InsertConfigInteger(pCfg, "Discard", 1);
1830
1831 if (fNonRotational)
1832 InsertConfigInteger(pCfg, "NonRotationalMedium", 1);
1833
1834 /* Pass all custom parameters. */
1835 bool fHostIP = true;
1836 bool fEncrypted = false;
1837 hrc = i_configMediumProperties(pCfg, ptrMedium, &fHostIP, &fEncrypted); H();
1838
1839 /* Create an inverted list of parents. */
1840 uImage--;
1841 ComPtr<IMedium> ptrParentMedium = ptrMedium;
1842 for (PCFGMNODE pParent = pCfg;; uImage--)
1843 {
1844 ComPtr<IMedium> ptrCurMedium;
1845 hrc = ptrParentMedium->COMGETTER(Parent)(ptrCurMedium.asOutParam()); H();
1846 if (ptrCurMedium.isNull())
1847 break;
1848
1849 PCFGMNODE pCur;
1850 InsertConfigNode(pParent, "Parent", &pCur);
1851 hrc = ptrCurMedium->COMGETTER(Location)(bstr.asOutParam()); H();
1852 InsertConfigString(pCur, "Path", bstr);
1853
1854 hrc = ptrCurMedium->COMGETTER(Format)(bstr.asOutParam()); H();
1855 InsertConfigString(pCur, "Format", bstr);
1856
1857 if (fSetupMerge)
1858 {
1859 if (uImage == uMergeSource)
1860 InsertConfigInteger(pCur, "MergeSource", 1);
1861 else if (uImage == uMergeTarget)
1862 InsertConfigInteger(pCur, "MergeTarget", 1);
1863 }
1864
1865 /* Configure medium properties. */
1866 hrc = i_configMediumProperties(pCur, ptrCurMedium, &fHostIP, &fEncrypted); H();
1867
1868 /* next */
1869 pParent = pCur;
1870 ptrParentMedium = ptrCurMedium;
1871 }
1872
1873 /* Custom code: put marker to not use host IP stack to driver
1874 * configuration node. Simplifies life of DrvVD a bit. */
1875 if (!fHostIP)
1876 InsertConfigInteger(pCfg, "HostIPStack", 0);
1877
1878 if (fEncrypted)
1879 m_cDisksEncrypted++;
1880 }
1881 else
1882 {
1883 /* Set empty drive flag for DVD or floppy without media. */
1884 if ( enmType == DeviceType_DVD
1885 || enmType == DeviceType_Floppy)
1886 InsertConfigInteger(pCfg, "EmptyDrive", 1);
1887 }
1888 }
1889#undef H
1890 }
1891 catch (ConfigError &x)
1892 {
1893 // InsertConfig threw something:
1894 return x.m_vrc;
1895 }
1896
1897 return VINF_SUCCESS;
1898}
1899
1900/**
1901 * Adds the medium properties to the CFGM tree.
1902 *
1903 * @returns VBox status code.
1904 * @param pCur The current CFGM node.
1905 * @param pMedium The medium object to configure.
1906 * @param pfHostIP Where to return the value of the \"HostIPStack\" property if found.
1907 * @param pfEncrypted Where to return whether the medium is encrypted.
1908 */
1909int Console::i_configMediumProperties(PCFGMNODE pCur, IMedium *pMedium, bool *pfHostIP, bool *pfEncrypted)
1910{
1911 /* Pass all custom parameters. */
1912 SafeArray<BSTR> aNames;
1913 SafeArray<BSTR> aValues;
1914 HRESULT hrc = pMedium->GetProperties(NULL, ComSafeArrayAsOutParam(aNames), ComSafeArrayAsOutParam(aValues));
1915 if ( SUCCEEDED(hrc)
1916 && aNames.size() != 0)
1917 {
1918 PCFGMNODE pVDC;
1919 InsertConfigNode(pCur, "VDConfig", &pVDC);
1920 for (size_t ii = 0; ii < aNames.size(); ++ii)
1921 {
1922 if (aValues[ii] && *aValues[ii])
1923 {
1924 Utf8Str const strName = aNames[ii];
1925 Utf8Str const strValue = aValues[ii];
1926 size_t offSlash = strName.find("/", 0);
1927 if ( offSlash != strName.npos
1928 && !strName.startsWith("Special/"))
1929 {
1930 com::Utf8Str strFilter;
1931 hrc = strFilter.assignEx(strName, 0, offSlash);
1932 if (FAILED(hrc))
1933 break;
1934
1935 com::Utf8Str strKey;
1936 hrc = strKey.assignEx(strName, offSlash + 1, strName.length() - offSlash - 1); /* Skip slash */
1937 if (FAILED(hrc))
1938 break;
1939
1940 PCFGMNODE pCfgFilterConfig = mpVMM->pfnCFGMR3GetChild(pVDC, strFilter.c_str());
1941 if (!pCfgFilterConfig)
1942 InsertConfigNode(pVDC, strFilter.c_str(), &pCfgFilterConfig);
1943
1944 InsertConfigString(pCfgFilterConfig, strKey.c_str(), strValue);
1945 }
1946 else
1947 {
1948 InsertConfigString(pVDC, strName.c_str(), strValue);
1949 if ( strName.compare("HostIPStack") == 0
1950 && strValue.compare("0") == 0)
1951 *pfHostIP = false;
1952 }
1953
1954 if ( strName.compare("CRYPT/KeyId") == 0
1955 && pfEncrypted)
1956 *pfEncrypted = true;
1957 }
1958 }
1959 }
1960
1961 return hrc;
1962}
1963
1964
1965/**
1966 * Configure proxy parameters the Network configuration tree.
1967 *
1968 * Parameters may differ depending on the IP address being accessed.
1969 *
1970 * @returns VBox status code.
1971 *
1972 * @param virtualBox The VirtualBox object.
1973 * @param pCfg Configuration node for the driver.
1974 * @param pcszPrefix The prefix for CFGM parameters: "Primary" or "Secondary".
1975 * @param strIpAddr The public IP address to be accessed via a proxy.
1976 *
1977 * @thread EMT
1978 */
1979int Console::i_configProxy(ComPtr<IVirtualBox> virtualBox, PCFGMNODE pCfg, const char *pcszPrefix, const com::Utf8Str &strIpAddr)
1980{
1981/** @todo r=bird: This code doesn't handle cleanup correctly and may leak
1982 * when hitting errors or throwing exceptions (bad_alloc). */
1983 RTHTTPPROXYINFO ProxyInfo;
1984 ComPtr<ISystemProperties> systemProperties;
1985 ProxyMode_T enmProxyMode;
1986 HRESULT hrc = virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam());
1987 if (FAILED(hrc))
1988 {
1989 LogRel(("CLOUD-NET: Failed to obtain system properties. hrc=%x\n", hrc));
1990 return false;
1991 }
1992 hrc = systemProperties->COMGETTER(ProxyMode)(&enmProxyMode);
1993 if (FAILED(hrc))
1994 {
1995 LogRel(("CLOUD-NET: Failed to obtain default machine folder. hrc=%x\n", hrc));
1996 return VERR_INTERNAL_ERROR;
1997 }
1998
1999 RTHTTP hHttp;
2000 int vrc = RTHttpCreate(&hHttp);
2001 if (RT_FAILURE(vrc))
2002 {
2003 LogRel(("CLOUD-NET: Failed to create HTTP context (vrc=%Rrc)\n", vrc));
2004 return vrc;
2005 }
2006
2007 char *pszProxyType = NULL;
2008
2009 if (enmProxyMode == ProxyMode_Manual)
2010 {
2011 /*
2012 * Unfortunately we cannot simply call RTHttpSetProxyByUrl because it never
2013 * exposes proxy settings. Calling RTHttpQueryProxyInfoForUrl afterward
2014 * won't help either as it uses system-wide proxy settings instead of
2015 * parameters we would have set with RTHttpSetProxyByUrl. Hence we parse
2016 * proxy URL ourselves here.
2017 */
2018 Bstr proxyUrl;
2019 hrc = systemProperties->COMGETTER(ProxyURL)(proxyUrl.asOutParam());
2020 if (FAILED(hrc))
2021 {
2022 LogRel(("CLOUD-NET: Failed to obtain proxy URL. hrc=%x\n", hrc));
2023 return false;
2024 }
2025 Utf8Str strProxyUrl = proxyUrl;
2026 if (!strProxyUrl.contains("://"))
2027 strProxyUrl = "http://" + strProxyUrl;
2028 const char *pcszProxyUrl = strProxyUrl.c_str();
2029 RTURIPARSED Parsed;
2030 vrc = RTUriParse(pcszProxyUrl, &Parsed);
2031 if (RT_FAILURE(vrc))
2032 {
2033 LogRel(("CLOUD-NET: Failed to parse proxy URL: %ls (vrc=%Rrc)\n", proxyUrl.raw(), vrc));
2034 return false;
2035 }
2036
2037 pszProxyType = RTUriParsedScheme(pcszProxyUrl, &Parsed);
2038 if (!pszProxyType)
2039 {
2040 LogRel(("CLOUD-NET: Failed to get proxy scheme from proxy URL: %s\n", pcszProxyUrl));
2041 return false;
2042 }
2043 RTStrToUpper(pszProxyType);
2044
2045 ProxyInfo.pszProxyHost = RTUriParsedAuthorityHost(pcszProxyUrl, &Parsed);
2046 if (!ProxyInfo.pszProxyHost)
2047 {
2048 LogRel(("CLOUD-NET: Failed to get proxy host name from proxy URL: %s\n", pcszProxyUrl));
2049 return false;
2050 }
2051 ProxyInfo.uProxyPort = RTUriParsedAuthorityPort(pcszProxyUrl, &Parsed);
2052 if (ProxyInfo.uProxyPort == UINT32_MAX)
2053 {
2054 LogRel(("CLOUD-NET: Failed to get proxy port from proxy URL: %s\n", pcszProxyUrl));
2055 return false;
2056 }
2057 ProxyInfo.pszProxyUsername = RTUriParsedAuthorityUsername(pcszProxyUrl, &Parsed);
2058 ProxyInfo.pszProxyPassword = RTUriParsedAuthorityPassword(pcszProxyUrl, &Parsed);
2059 }
2060 else if (enmProxyMode == ProxyMode_System)
2061 {
2062 vrc = RTHttpUseSystemProxySettings(hHttp);
2063 if (RT_FAILURE(vrc))
2064 {
2065 LogRel(("%s: RTHttpUseSystemProxySettings() failed: %Rrc", __FUNCTION__, vrc));
2066 RTHttpDestroy(hHttp);
2067 return vrc;
2068 }
2069 vrc = RTHttpQueryProxyInfoForUrl(hHttp, ("http://" + strIpAddr).c_str(), &ProxyInfo);
2070 RTHttpDestroy(hHttp);
2071 if (RT_FAILURE(vrc))
2072 {
2073 LogRel(("CLOUD-NET: Failed to get proxy for %s (vrc=%Rrc)\n", strIpAddr.c_str(), vrc));
2074 return vrc;
2075 }
2076
2077 switch (ProxyInfo.enmProxyType)
2078 {
2079 case RTHTTPPROXYTYPE_NOPROXY:
2080 /* Nothing to do */
2081 return VINF_SUCCESS;
2082 case RTHTTPPROXYTYPE_HTTP:
2083 pszProxyType = RTStrDup("HTTP");
2084 break;
2085 case RTHTTPPROXYTYPE_HTTPS:
2086 case RTHTTPPROXYTYPE_SOCKS4:
2087 case RTHTTPPROXYTYPE_SOCKS5:
2088 /* break; -- Fall through until support is implemented */
2089 case RTHTTPPROXYTYPE_UNKNOWN:
2090 case RTHTTPPROXYTYPE_INVALID:
2091 case RTHTTPPROXYTYPE_END:
2092 case RTHTTPPROXYTYPE_32BIT_HACK:
2093 LogRel(("CLOUD-NET: Unsupported proxy type %u\n", ProxyInfo.enmProxyType));
2094 RTHttpFreeProxyInfo(&ProxyInfo);
2095 return VERR_INVALID_PARAMETER;
2096 }
2097 }
2098 else
2099 {
2100 Assert(enmProxyMode == ProxyMode_NoProxy);
2101 return VINF_SUCCESS;
2102 }
2103
2104 /* Resolve proxy host name to IP address if necessary */
2105 RTNETADDR addr;
2106 RTSocketParseInetAddress(ProxyInfo.pszProxyHost, ProxyInfo.uProxyPort, &addr);
2107 if (addr.enmType != RTNETADDRTYPE_IPV4)
2108 {
2109 LogRel(("CLOUD-NET: Unsupported address type %u\n", addr.enmType));
2110 RTHttpFreeProxyInfo(&ProxyInfo);
2111 return VERR_INVALID_PARAMETER;
2112 }
2113
2114 InsertConfigString( pCfg, Utf8StrFmt("%sProxyType", pcszPrefix).c_str(), pszProxyType);
2115 InsertConfigInteger( pCfg, Utf8StrFmt("%sProxyPort", pcszPrefix).c_str(), ProxyInfo.uProxyPort);
2116 if (ProxyInfo.pszProxyHost)
2117 InsertConfigStringF( pCfg, Utf8StrFmt("%sProxyHost", pcszPrefix).c_str(), "%RTnaipv4", addr.uAddr.IPv4);
2118 if (ProxyInfo.pszProxyUsername)
2119 InsertConfigString( pCfg, Utf8StrFmt("%sProxyUser", pcszPrefix).c_str(), ProxyInfo.pszProxyUsername);
2120 if (ProxyInfo.pszProxyPassword)
2121 InsertConfigPassword(pCfg, Utf8StrFmt("%sProxyPassword", pcszPrefix).c_str(), ProxyInfo.pszProxyPassword);
2122
2123 RTHttpFreeProxyInfo(&ProxyInfo);
2124 RTStrFree(pszProxyType);
2125 return vrc;
2126}
2127
2128
2129/**
2130 * Construct the Network configuration tree
2131 *
2132 * @returns VBox status code.
2133 *
2134 * @param pszDevice The PDM device name.
2135 * @param uInstance The PDM device instance.
2136 * @param uLun The PDM LUN number of the drive.
2137 * @param aNetworkAdapter The network adapter whose attachment needs to be changed
2138 * @param pCfg Configuration node for the device
2139 * @param pLunL0 To store the pointer to the LUN#0.
2140 * @param pInst The instance CFGM node
2141 * @param fAttachDetach To determine if the network attachment should
2142 * be attached/detached after/before
2143 * configuration.
2144 * @param fIgnoreConnectFailure
2145 * True if connection failures should be ignored
2146 * (makes only sense for bridged/host-only networks).
2147 * @param pUVM The usermode VM handle.
2148 * @param pVMM The VMM vtable.
2149 *
2150 * @note Locks this object for writing.
2151 * @thread EMT
2152 */
2153int Console::i_configNetwork(const char *pszDevice,
2154 unsigned uInstance,
2155 unsigned uLun,
2156 INetworkAdapter *aNetworkAdapter,
2157 PCFGMNODE pCfg,
2158 PCFGMNODE pLunL0,
2159 PCFGMNODE pInst,
2160 bool fAttachDetach,
2161 bool fIgnoreConnectFailure,
2162 PUVM pUVM,
2163 PCVMMR3VTABLE pVMM)
2164{
2165 RT_NOREF(fIgnoreConnectFailure);
2166 AutoCaller autoCaller(this);
2167 AssertComRCReturn(autoCaller.hrc(), VERR_ACCESS_DENIED);
2168
2169 // InsertConfig* throws
2170 try
2171 {
2172 int vrc = VINF_SUCCESS;
2173 HRESULT hrc;
2174 Bstr bstr;
2175
2176#ifdef VBOX_WITH_CLOUD_NET
2177 /* We'll need device's pCfg for cloud attachments */
2178 PCFGMNODE pDevCfg = pCfg;
2179#endif /* VBOX_WITH_CLOUD_NET */
2180
2181#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
2182
2183 /*
2184 * Locking the object before doing VMR3* calls is quite safe here, since
2185 * we're on EMT. Write lock is necessary because we indirectly modify the
2186 * meAttachmentType member.
2187 */
2188 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2189
2190 ComPtr<IMachine> pMachine = i_machine();
2191
2192 ComPtr<IVirtualBox> virtualBox;
2193 hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam()); H();
2194
2195 ComPtr<IHost> host;
2196 hrc = virtualBox->COMGETTER(Host)(host.asOutParam()); H();
2197
2198 BOOL fSniffer;
2199 hrc = aNetworkAdapter->COMGETTER(TraceEnabled)(&fSniffer); H();
2200
2201 NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy;
2202 hrc = aNetworkAdapter->COMGETTER(PromiscModePolicy)(&enmPromiscModePolicy); H();
2203 const char *pszPromiscuousGuestPolicy;
2204 switch (enmPromiscModePolicy)
2205 {
2206 case NetworkAdapterPromiscModePolicy_Deny: pszPromiscuousGuestPolicy = "deny"; break;
2207 case NetworkAdapterPromiscModePolicy_AllowNetwork: pszPromiscuousGuestPolicy = "allow-network"; break;
2208 case NetworkAdapterPromiscModePolicy_AllowAll: pszPromiscuousGuestPolicy = "allow-all"; break;
2209 default: AssertFailedReturn(VERR_INTERNAL_ERROR_4);
2210 }
2211
2212 if (fAttachDetach)
2213 {
2214 vrc = pVMM->pfnPDMR3DeviceDetach(pUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/);
2215 if (vrc == VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN)
2216 vrc = VINF_SUCCESS;
2217 AssertLogRelRCReturn(vrc, vrc);
2218
2219 /* Nuke anything which might have been left behind. */
2220 pVMM->pfnCFGMR3RemoveNode(pVMM->pfnCFGMR3GetChildF(pInst, "LUN#%u", uLun));
2221 }
2222
2223 Bstr networkName, trunkName, trunkType;
2224 NetworkAttachmentType_T eAttachmentType;
2225 hrc = aNetworkAdapter->COMGETTER(AttachmentType)(&eAttachmentType); H();
2226
2227#ifdef VBOX_WITH_NETSHAPER
2228 ComObjPtr<IBandwidthGroup> pBwGroup;
2229 Bstr bstrBwGroup;
2230 hrc = aNetworkAdapter->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
2231
2232 if (!pBwGroup.isNull())
2233 {
2234 hrc = pBwGroup->COMGETTER(Name)(bstrBwGroup.asOutParam()); H();
2235 }
2236#endif /* VBOX_WITH_NETSHAPER */
2237
2238 AssertMsg(uLun == 0, ("Network attachments with LUN > 0 are not supported yet\n"));
2239 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", uLun);
2240
2241 /*
2242 * Do not insert neither a shaper nor a sniffer if we are not attached to anything.
2243 * This way we can easily detect if we are attached to anything at the device level.
2244 */
2245#ifdef VBOX_WITH_NETSHAPER
2246 if (bstrBwGroup.isNotEmpty() && eAttachmentType != NetworkAttachmentType_Null)
2247 {
2248 InsertConfigString(pLunL0, "Driver", "NetShaper");
2249 InsertConfigNode(pLunL0, "Config", &pCfg);
2250 InsertConfigString(pCfg, "BwGroup", bstrBwGroup);
2251 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
2252 }
2253#endif /* VBOX_WITH_NETSHAPER */
2254
2255 if (fSniffer && eAttachmentType != NetworkAttachmentType_Null)
2256 {
2257 InsertConfigString(pLunL0, "Driver", "NetSniffer");
2258 InsertConfigNode(pLunL0, "Config", &pCfg);
2259 hrc = aNetworkAdapter->COMGETTER(TraceFile)(bstr.asOutParam()); H();
2260 if (!bstr.isEmpty()) /* check convention for indicating default file. */
2261 InsertConfigString(pCfg, "File", bstr);
2262 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
2263 }
2264
2265 switch (eAttachmentType)
2266 {
2267 case NetworkAttachmentType_Null:
2268 break;
2269
2270 case NetworkAttachmentType_NAT:
2271 {
2272 ComPtr<INATEngine> natEngine;
2273 hrc = aNetworkAdapter->COMGETTER(NATEngine)(natEngine.asOutParam()); H();
2274 InsertConfigString(pLunL0, "Driver", "NAT");
2275 InsertConfigNode(pLunL0, "Config", &pCfg);
2276
2277 /* Configure TFTP prefix and boot filename. */
2278 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
2279 if (!bstr.isEmpty())
2280 InsertConfigStringF(pCfg, "TFTPPrefix", "%ls%c%s", bstr.raw(), RTPATH_DELIMITER, "TFTP");
2281 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
2282 InsertConfigStringF(pCfg, "BootFile", "%ls.pxe", bstr.raw());
2283
2284 hrc = natEngine->COMGETTER(Network)(bstr.asOutParam()); H();
2285 if (!bstr.isEmpty())
2286 InsertConfigString(pCfg, "Network", bstr);
2287 else
2288 {
2289 ULONG uSlot;
2290 hrc = aNetworkAdapter->COMGETTER(Slot)(&uSlot); H();
2291 InsertConfigStringF(pCfg, "Network", "10.0.%d.0/24", uSlot+2);
2292 }
2293 hrc = natEngine->COMGETTER(HostIP)(bstr.asOutParam()); H();
2294 if (!bstr.isEmpty())
2295 InsertConfigString(pCfg, "BindIP", bstr);
2296 ULONG mtu = 0;
2297 ULONG sockSnd = 0;
2298 ULONG sockRcv = 0;
2299 ULONG tcpSnd = 0;
2300 ULONG tcpRcv = 0;
2301 hrc = natEngine->GetNetworkSettings(&mtu, &sockSnd, &sockRcv, &tcpSnd, &tcpRcv); H();
2302 if (mtu)
2303 InsertConfigInteger(pCfg, "SlirpMTU", mtu);
2304 if (sockRcv)
2305 InsertConfigInteger(pCfg, "SockRcv", sockRcv);
2306 if (sockSnd)
2307 InsertConfigInteger(pCfg, "SockSnd", sockSnd);
2308 if (tcpRcv)
2309 InsertConfigInteger(pCfg, "TcpRcv", tcpRcv);
2310 if (tcpSnd)
2311 InsertConfigInteger(pCfg, "TcpSnd", tcpSnd);
2312 hrc = natEngine->COMGETTER(TFTPPrefix)(bstr.asOutParam()); H();
2313 if (!bstr.isEmpty())
2314 {
2315 RemoveConfigValue(pCfg, "TFTPPrefix");
2316 InsertConfigString(pCfg, "TFTPPrefix", bstr);
2317 }
2318 hrc = natEngine->COMGETTER(TFTPBootFile)(bstr.asOutParam()); H();
2319 if (!bstr.isEmpty())
2320 {
2321 RemoveConfigValue(pCfg, "BootFile");
2322 InsertConfigString(pCfg, "BootFile", bstr);
2323 }
2324 hrc = natEngine->COMGETTER(TFTPNextServer)(bstr.asOutParam()); H();
2325 if (!bstr.isEmpty())
2326 InsertConfigString(pCfg, "NextServer", bstr);
2327 BOOL fDNSFlag;
2328 hrc = natEngine->COMGETTER(DNSPassDomain)(&fDNSFlag); H();
2329 InsertConfigInteger(pCfg, "PassDomain", fDNSFlag);
2330 hrc = natEngine->COMGETTER(DNSProxy)(&fDNSFlag); H();
2331 InsertConfigInteger(pCfg, "DNSProxy", fDNSFlag);
2332 hrc = natEngine->COMGETTER(DNSUseHostResolver)(&fDNSFlag); H();
2333 InsertConfigInteger(pCfg, "UseHostResolver", fDNSFlag);
2334
2335 ULONG aliasMode;
2336 hrc = natEngine->COMGETTER(AliasMode)(&aliasMode); H();
2337 InsertConfigInteger(pCfg, "AliasMode", aliasMode);
2338
2339 BOOL fLocalhostReachable;
2340 hrc = natEngine->COMGETTER(LocalhostReachable)(&fLocalhostReachable); H();
2341 InsertConfigInteger(pCfg, "LocalhostReachable", fLocalhostReachable);
2342
2343 /* forward broadcast packets */
2344 BOOL fForwardBroadcast = FALSE;
2345 hrc = natEngine->COMGETTER(ForwardBroadcast)(&fForwardBroadcast); H();
2346 InsertConfigInteger(pCfg, "ForwardBroadcast", fForwardBroadcast);
2347
2348 /* port-forwarding */
2349 SafeArray<BSTR> pfs;
2350 hrc = natEngine->COMGETTER(Redirects)(ComSafeArrayAsOutParam(pfs)); H();
2351
2352 PCFGMNODE pPFTree = NULL;
2353 if (pfs.size() > 0)
2354 InsertConfigNode(pCfg, "PortForwarding", &pPFTree);
2355
2356 for (unsigned int i = 0; i < pfs.size(); ++i)
2357 {
2358 PCFGMNODE pPF = NULL; /* /Devices/Dev/.../Config/PortForwarding/$n/ */
2359
2360 uint16_t port = 0;
2361 Utf8Str utf = pfs[i];
2362 Utf8Str strName;
2363 Utf8Str strProto;
2364 Utf8Str strHostPort;
2365 Utf8Str strHostIP;
2366 Utf8Str strGuestPort;
2367 Utf8Str strGuestIP;
2368 size_t pos, ppos;
2369 pos = ppos = 0;
2370#define ITERATE_TO_NEXT_TERM(res, str, pos, ppos) \
2371 { \
2372 pos = str.find(",", ppos); \
2373 if (pos == Utf8Str::npos) \
2374 { \
2375 Log(( #res " extracting from %s is failed\n", str.c_str())); \
2376 continue; \
2377 } \
2378 res = str.substr(ppos, pos - ppos); \
2379 Log2((#res " %s pos:%d, ppos:%d\n", res.c_str(), pos, ppos)); \
2380 ppos = pos + 1; \
2381 } /* no do { ... } while because of 'continue' */
2382 ITERATE_TO_NEXT_TERM(strName, utf, pos, ppos);
2383 ITERATE_TO_NEXT_TERM(strProto, utf, pos, ppos);
2384 ITERATE_TO_NEXT_TERM(strHostIP, utf, pos, ppos);
2385 ITERATE_TO_NEXT_TERM(strHostPort, utf, pos, ppos);
2386 ITERATE_TO_NEXT_TERM(strGuestIP, utf, pos, ppos);
2387 strGuestPort = utf.substr(ppos, utf.length() - ppos);
2388#undef ITERATE_TO_NEXT_TERM
2389
2390 uint32_t proto = strProto.toUInt32();
2391 bool fValid = true;
2392 switch (proto)
2393 {
2394 case NATProtocol_UDP:
2395 strProto = "UDP";
2396 break;
2397 case NATProtocol_TCP:
2398 strProto = "TCP";
2399 break;
2400 default:
2401 fValid = false;
2402 }
2403 /* continue with next rule if no valid proto was passed */
2404 if (!fValid)
2405 continue;
2406
2407 InsertConfigNodeF(pPFTree, &pPF, "%u", i);
2408
2409 if (!strName.isEmpty())
2410 InsertConfigString(pPF, "Name", strName);
2411
2412 InsertConfigString(pPF, "Protocol", strProto);
2413
2414 if (!strHostIP.isEmpty())
2415 InsertConfigString(pPF, "BindIP", strHostIP);
2416
2417 if (!strGuestIP.isEmpty())
2418 InsertConfigString(pPF, "GuestIP", strGuestIP);
2419
2420 port = RTStrToUInt16(strHostPort.c_str());
2421 if (port)
2422 InsertConfigInteger(pPF, "HostPort", port);
2423
2424 port = RTStrToUInt16(strGuestPort.c_str());
2425 if (port)
2426 InsertConfigInteger(pPF, "GuestPort", port);
2427 }
2428 break;
2429 }
2430
2431 case NetworkAttachmentType_Bridged:
2432 {
2433#if (defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)) && !defined(VBOX_WITH_NETFLT)
2434 hrc = i_attachToTapInterface(aNetworkAdapter);
2435 if (FAILED(hrc))
2436 {
2437 switch (hrc)
2438 {
2439 case E_ACCESSDENIED:
2440 return pVMM->pfnVMR3SetError(pUVM, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
2441 "Failed to open '/dev/net/tun' for read/write access. Please check the "
2442 "permissions of that node. Either run 'chmod 0666 /dev/net/tun' or "
2443 "change the group of that node and make yourself a member of that group. "
2444 "Make sure that these changes are permanent, especially if you are "
2445 "using udev"));
2446 default:
2447 AssertMsgFailed(("Could not attach to host interface! Bad!\n"));
2448 return pVMM->pfnVMR3SetError(pUVM, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,
2449 N_("Failed to initialize Host Interface Networking"));
2450 }
2451 }
2452
2453 Assert((intptr_t)maTapFD[uInstance] >= 0);
2454 if ((intptr_t)maTapFD[uInstance] >= 0)
2455 {
2456 InsertConfigString(pLunL0, "Driver", "HostInterface");
2457 InsertConfigNode(pLunL0, "Config", &pCfg);
2458 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
2459 }
2460
2461#elif defined(VBOX_WITH_NETFLT)
2462 /*
2463 * This is the new VBoxNetFlt+IntNet stuff.
2464 */
2465 Bstr BridgedIfName;
2466 hrc = aNetworkAdapter->COMGETTER(BridgedInterface)(BridgedIfName.asOutParam());
2467 if (FAILED(hrc))
2468 {
2469 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(BridgedInterface) failed, hrc (0x%x)\n", hrc));
2470 H();
2471 }
2472
2473 Utf8Str BridgedIfNameUtf8(BridgedIfName);
2474 const char *pszBridgedIfName = BridgedIfNameUtf8.c_str();
2475
2476 ComPtr<IHostNetworkInterface> hostInterface;
2477 hrc = host->FindHostNetworkInterfaceByName(BridgedIfName.raw(),
2478 hostInterface.asOutParam());
2479 if (!SUCCEEDED(hrc))
2480 {
2481 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: FindByName failed, hrc=%Rhrc (0x%x)\n", hrc, hrc));
2482 return pVMM->pfnVMR3SetError(pUVM, VERR_INTERNAL_ERROR, RT_SRC_POS,
2483 N_("Nonexistent host networking interface, name '%ls'"),
2484 BridgedIfName.raw());
2485 }
2486
2487# if defined(RT_OS_DARWIN)
2488 /* The name is in the format 'ifX: long name', chop it off at the colon. */
2489 char szTrunk[INTNET_MAX_TRUNK_NAME];
2490 RTStrCopy(szTrunk, sizeof(szTrunk), pszBridgedIfName);
2491 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
2492// Quick fix for @bugref{5633}
2493// if (!pszColon)
2494// {
2495// /*
2496// * Dynamic changing of attachment causes an attempt to configure
2497// * network with invalid host adapter (as it is must be changed before
2498// * the attachment), calling Detach here will cause a deadlock.
2499// * See @bugref{4750}.
2500// * hrc = aNetworkAdapter->Detach(); H();
2501// */
2502// return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
2503// N_("Malformed host interface networking name '%ls'"),
2504// BridgedIfName.raw());
2505// }
2506 if (pszColon)
2507 *pszColon = '\0';
2508 const char *pszTrunk = szTrunk;
2509
2510# elif defined(RT_OS_SOLARIS)
2511 /* The name is in the format 'ifX[:1] - long name, chop it off at space. */
2512 char szTrunk[256];
2513 strlcpy(szTrunk, pszBridgedIfName, sizeof(szTrunk));
2514 char *pszSpace = (char *)memchr(szTrunk, ' ', sizeof(szTrunk));
2515
2516 /*
2517 * Currently don't bother about malformed names here for the sake of people using
2518 * VBoxManage and setting only the NIC name from there. If there is a space we
2519 * chop it off and proceed, otherwise just use whatever we've got.
2520 */
2521 if (pszSpace)
2522 *pszSpace = '\0';
2523
2524 /* Chop it off at the colon (zone naming eg: e1000g:1 we need only the e1000g) */
2525 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
2526 if (pszColon)
2527 *pszColon = '\0';
2528
2529 const char *pszTrunk = szTrunk;
2530
2531# elif defined(RT_OS_WINDOWS)
2532 HostNetworkInterfaceType_T eIfType;
2533 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
2534 if (FAILED(hrc))
2535 {
2536 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
2537 H();
2538 }
2539
2540 if (eIfType != HostNetworkInterfaceType_Bridged)
2541 return pVMM->pfnVMR3SetError(pUVM, VERR_INTERNAL_ERROR, RT_SRC_POS,
2542 N_("Interface ('%ls') is not a Bridged Adapter interface"),
2543 BridgedIfName.raw());
2544
2545 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
2546 if (FAILED(hrc))
2547 {
2548 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
2549 H();
2550 }
2551 Guid hostIFGuid(bstr);
2552
2553 INetCfg *pNc;
2554 ComPtr<INetCfgComponent> pAdaptorComponent;
2555 LPWSTR pszApp;
2556
2557 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
2558 Assert(hrc == S_OK);
2559 if (hrc != S_OK)
2560 {
2561 LogRel(("NetworkAttachmentType_Bridged: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
2562 H();
2563 }
2564
2565 /* get the adapter's INetCfgComponent*/
2566 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
2567 pAdaptorComponent.asOutParam());
2568 if (hrc != S_OK)
2569 {
2570 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
2571 LogRel(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)\n", hrc));
2572 H();
2573 }
2574# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
2575 char szTrunkName[INTNET_MAX_TRUNK_NAME];
2576 char *pszTrunkName = szTrunkName;
2577 wchar_t * pswzBindName;
2578 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
2579 Assert(hrc == S_OK);
2580 if (hrc == S_OK)
2581 {
2582 int cwBindName = (int)wcslen(pswzBindName) + 1;
2583 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
2584 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
2585 {
2586 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
2587 pszTrunkName += cbFullBindNamePrefix-1;
2588 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
2589 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
2590 {
2591 DWORD err = GetLastError();
2592 hrc = HRESULT_FROM_WIN32(err);
2593 AssertMsgFailed(("hrc=%Rhrc %#x\n", hrc, hrc));
2594 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
2595 hrc, hrc, err));
2596 }
2597 }
2598 else
2599 {
2600 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: insufficient szTrunkName buffer space\n"));
2601 /** @todo set appropriate error code */
2602 hrc = E_FAIL;
2603 }
2604
2605 if (hrc != S_OK)
2606 {
2607 AssertFailed();
2608 CoTaskMemFree(pswzBindName);
2609 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
2610 H();
2611 }
2612
2613 /* we're not freeing the bind name since we'll use it later for detecting wireless*/
2614 }
2615 else
2616 {
2617 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
2618 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)",
2619 hrc));
2620 H();
2621 }
2622
2623 const char *pszTrunk = szTrunkName;
2624 /* we're not releasing the INetCfg stuff here since we use it later to figure out whether it is wireless */
2625
2626# elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
2627# if defined(RT_OS_FREEBSD)
2628 /*
2629 * If we bridge to a tap interface open it the `old' direct way.
2630 * This works and performs better than bridging a physical
2631 * interface via the current FreeBSD vboxnetflt implementation.
2632 */
2633 if (!strncmp(pszBridgedIfName, RT_STR_TUPLE("tap"))) {
2634 hrc = i_attachToTapInterface(aNetworkAdapter);
2635 if (FAILED(hrc))
2636 {
2637 switch (hrc)
2638 {
2639 case E_ACCESSDENIED:
2640 return pVMM->pfnVMR3SetError(pUVM, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
2641 "Failed to open '/dev/%s' for read/write access. Please check the "
2642 "permissions of that node, and that the net.link.tap.user_open "
2643 "sysctl is set. Either run 'chmod 0666 /dev/%s' or change the "
2644 "group of that node to vboxusers and make yourself a member of "
2645 "that group. Make sure that these changes are permanent."),
2646 pszBridgedIfName, pszBridgedIfName);
2647 default:
2648 AssertMsgFailed(("Could not attach to tap interface! Bad!\n"));
2649 return pVMM->pfnVMR3SetError(pUVM, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,
2650 N_("Failed to initialize Host Interface Networking"));
2651 }
2652 }
2653
2654 Assert((intptr_t)maTapFD[uInstance] >= 0);
2655 if ((intptr_t)maTapFD[uInstance] >= 0)
2656 {
2657 InsertConfigString(pLunL0, "Driver", "HostInterface");
2658 InsertConfigNode(pLunL0, "Config", &pCfg);
2659 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
2660 }
2661 break;
2662 }
2663# endif
2664 /** @todo Check for malformed names. */
2665 const char *pszTrunk = pszBridgedIfName;
2666
2667 /* Issue a warning if the interface is down */
2668 {
2669 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
2670 if (iSock >= 0)
2671 {
2672 struct ifreq Req;
2673 RT_ZERO(Req);
2674 RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pszBridgedIfName);
2675 if (ioctl(iSock, SIOCGIFFLAGS, &Req) >= 0)
2676 if ((Req.ifr_flags & IFF_UP) == 0)
2677 i_atVMRuntimeErrorCallbackF(0, "BridgedInterfaceDown",
2678 N_("Bridged interface %s is down. Guest will not be able to use this interface"),
2679 pszBridgedIfName);
2680
2681 close(iSock);
2682 }
2683 }
2684# ifdef VBOXNETFLT_LINUX_NAMESPACE_SUPPORT
2685 RTUUID IfaceUuid;
2686 Bstr IfId;
2687 hrc = hostInterface->COMGETTER(Id)(IfId.asOutParam()); H();
2688 vrc = RTUuidFromUtf16(&IfaceUuid, IfId.raw());
2689 AssertRCReturn(vrc, vrc);
2690 char szTrunkNameWithNamespace[INTNET_MAX_TRUNK_NAME];
2691 RTStrPrintf(szTrunkNameWithNamespace, sizeof(szTrunkNameWithNamespace), "%u/%s",
2692 IfaceUuid.au32[0], pszTrunk);
2693 pszTrunk = szTrunkNameWithNamespace;
2694# endif
2695
2696# else
2697# error "PORTME (VBOX_WITH_NETFLT)"
2698# endif
2699
2700# if defined(RT_OS_DARWIN) && defined(VBOX_WITH_VMNET)
2701 InsertConfigString(pLunL0, "Driver", "VMNet");
2702 InsertConfigNode(pLunL0, "Config", &pCfg);
2703 InsertConfigString(pCfg, "Trunk", pszTrunk);
2704 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
2705# else
2706 InsertConfigString(pLunL0, "Driver", "IntNet");
2707 InsertConfigNode(pLunL0, "Config", &pCfg);
2708 InsertConfigString(pCfg, "Trunk", pszTrunk);
2709 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
2710 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure);
2711 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
2712 char szNetwork[INTNET_MAX_NETWORK_NAME];
2713
2714# if defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN)
2715 /*
2716 * 'pszTrunk' contains just the interface name required in ring-0, while 'pszBridgedIfName' contains
2717 * interface name + optional description. We must not pass any description to the VM as it can differ
2718 * for the same interface name, eg: "nge0 - ethernet" (GUI) vs "nge0" (VBoxManage).
2719 */
2720 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszTrunk);
2721# else
2722 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszBridgedIfName);
2723# endif
2724 InsertConfigString(pCfg, "Network", szNetwork);
2725 networkName = Bstr(szNetwork);
2726 trunkName = Bstr(pszTrunk);
2727 trunkType = Bstr(TRUNKTYPE_NETFLT);
2728
2729 BOOL fSharedMacOnWire = false;
2730 hrc = hostInterface->COMGETTER(Wireless)(&fSharedMacOnWire);
2731 if (FAILED(hrc))
2732 {
2733 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Wireless) failed, hrc (0x%x)\n", hrc));
2734 H();
2735 }
2736 else if (fSharedMacOnWire)
2737 {
2738 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
2739 Log(("Set SharedMacOnWire\n"));
2740 }
2741
2742# if defined(RT_OS_SOLARIS)
2743# if 0 /* bird: this is a bit questionable and might cause more trouble than its worth. */
2744 /* Zone access restriction, don't allow snooping the global zone. */
2745 zoneid_t ZoneId = getzoneid();
2746 if (ZoneId != GLOBAL_ZONEID)
2747 {
2748 InsertConfigInteger(pCfg, "IgnoreAllPromisc", true);
2749 }
2750# endif
2751# endif
2752# endif
2753
2754#elif defined(RT_OS_WINDOWS) /* not defined NetFlt */
2755 /* NOTHING TO DO HERE */
2756#elif defined(RT_OS_LINUX)
2757/// @todo aleksey: is there anything to be done here?
2758#elif defined(RT_OS_FREEBSD)
2759/** @todo FreeBSD: Check out this later (HIF networking). */
2760#else
2761# error "Port me"
2762#endif
2763 break;
2764 }
2765
2766 case NetworkAttachmentType_Internal:
2767 {
2768 hrc = aNetworkAdapter->COMGETTER(InternalNetwork)(bstr.asOutParam()); H();
2769 if (!bstr.isEmpty())
2770 {
2771 InsertConfigString(pLunL0, "Driver", "IntNet");
2772 InsertConfigNode(pLunL0, "Config", &pCfg);
2773 InsertConfigString(pCfg, "Network", bstr);
2774 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
2775 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
2776 networkName = bstr;
2777 trunkType = Bstr(TRUNKTYPE_WHATEVER);
2778 }
2779 break;
2780 }
2781
2782 case NetworkAttachmentType_HostOnly:
2783 {
2784 InsertConfigString(pLunL0, "Driver", "IntNet");
2785 InsertConfigNode(pLunL0, "Config", &pCfg);
2786
2787 Bstr HostOnlyName;
2788 hrc = aNetworkAdapter->COMGETTER(HostOnlyInterface)(HostOnlyName.asOutParam());
2789 if (FAILED(hrc))
2790 {
2791 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(HostOnlyInterface) failed, hrc (0x%x)\n", hrc));
2792 H();
2793 }
2794
2795 Utf8Str HostOnlyNameUtf8(HostOnlyName);
2796 const char *pszHostOnlyName = HostOnlyNameUtf8.c_str();
2797#ifdef VBOX_WITH_VMNET
2798 /* Check if the matching host-only network has already been created. */
2799 Bstr bstrLowerIP, bstrUpperIP, bstrNetworkMask;
2800 BstrFmt bstrNetworkName("Legacy %s Network", pszHostOnlyName);
2801 ComPtr<IHostOnlyNetwork> hostOnlyNetwork;
2802 hrc = virtualBox->FindHostOnlyNetworkByName(bstrNetworkName.raw(), hostOnlyNetwork.asOutParam());
2803 if (FAILED(hrc))
2804 {
2805 /*
2806 * With VMNET there is no VBoxNetAdp to create vboxnetX adapters,
2807 * which means that the Host object won't be able to re-create
2808 * them from extra data. Go through existing DHCP/adapter config
2809 * to derive the parameters for the new network.
2810 */
2811 BstrFmt bstrOldNetworkName("HostInterfaceNetworking-%s", pszHostOnlyName);
2812 ComPtr<IDHCPServer> dhcpServer;
2813 hrc = virtualBox->FindDHCPServerByNetworkName(bstrOldNetworkName.raw(),
2814 dhcpServer.asOutParam());
2815 if (SUCCEEDED(hrc))
2816 {
2817 /* There is a DHCP server available for this network. */
2818 hrc = dhcpServer->COMGETTER(LowerIP)(bstrLowerIP.asOutParam());
2819 if (FAILED(hrc))
2820 {
2821 LogRel(("Console::i_configNetwork: COMGETTER(LowerIP) failed, hrc (%Rhrc)\n", hrc));
2822 H();
2823 }
2824 hrc = dhcpServer->COMGETTER(UpperIP)(bstrUpperIP.asOutParam());
2825 if (FAILED(hrc))
2826 {
2827 LogRel(("Console::i_configNetwork: COMGETTER(UpperIP) failed, hrc (%Rhrc)\n", hrc));
2828 H();
2829 }
2830 hrc = dhcpServer->COMGETTER(NetworkMask)(bstrNetworkMask.asOutParam());
2831 if (FAILED(hrc))
2832 {
2833 LogRel(("Console::i_configNetwork: COMGETTER(NetworkMask) failed, hrc (%Rhrc)\n", hrc));
2834 H();
2835 }
2836 }
2837 else
2838 {
2839 /* No DHCP server for this hostonly interface, let's look at extra data */
2840 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPAddress",
2841 pszHostOnlyName).raw(),
2842 bstrLowerIP.asOutParam());
2843 if (SUCCEEDED(hrc) && !bstrLowerIP.isEmpty())
2844 virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPNetMask",
2845 pszHostOnlyName).raw(),
2846 bstrNetworkMask.asOutParam());
2847 }
2848 RTNETADDRIPV4 ipAddr, ipMask;
2849 vrc = bstrLowerIP.isEmpty() ? VERR_MISSING : RTNetStrToIPv4Addr(Utf8Str(bstrLowerIP).c_str(), &ipAddr);
2850 if (RT_FAILURE(vrc))
2851 {
2852 /* We failed to locate any valid config of this vboxnetX interface, assume defaults. */
2853 LogRel(("NetworkAttachmentType_HostOnly: Invalid or missing lower IP '%ls', using '%ls' instead.\n",
2854 bstrLowerIP.raw(), getDefaultIPv4Address(Bstr(pszHostOnlyName)).raw()));
2855 bstrLowerIP = getDefaultIPv4Address(Bstr(pszHostOnlyName));
2856 bstrNetworkMask.setNull();
2857 bstrUpperIP.setNull();
2858 vrc = RTNetStrToIPv4Addr(Utf8Str(bstrLowerIP).c_str(), &ipAddr);
2859 AssertLogRelMsgReturn(RT_SUCCESS(vrc), ("RTNetStrToIPv4Addr(%ls) failed, vrc=%Rrc\n", bstrLowerIP.raw(), vrc),
2860 VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
2861 }
2862 vrc = bstrNetworkMask.isEmpty() ? VERR_MISSING : RTNetStrToIPv4Addr(Utf8Str(bstrNetworkMask).c_str(), &ipMask);
2863 if (RT_FAILURE(vrc))
2864 {
2865 LogRel(("NetworkAttachmentType_HostOnly: Invalid or missing network mask '%ls', using '%s' instead.\n",
2866 bstrNetworkMask.raw(), VBOXNET_IPV4MASK_DEFAULT));
2867 bstrNetworkMask = VBOXNET_IPV4MASK_DEFAULT;
2868 vrc = RTNetStrToIPv4Addr(Utf8Str(bstrNetworkMask).c_str(), &ipMask);
2869 AssertLogRelMsgReturn(RT_SUCCESS(vrc), ("RTNetStrToIPv4Addr(%ls) failed, vrc=%Rrc\n", bstrNetworkMask.raw(), vrc),
2870 VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
2871 }
2872 vrc = bstrUpperIP.isEmpty() ? VERR_MISSING : RTNetStrToIPv4Addr(Utf8Str(bstrUpperIP).c_str(), &ipAddr);
2873 if (RT_FAILURE(vrc))
2874 {
2875 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? */
2876 LogRel(("NetworkAttachmentType_HostOnly: Invalid or missing upper IP '%ls', using '%RTnaipv4' instead.\n",
2877 bstrUpperIP.raw(), ipAddr));
2878 bstrUpperIP = BstrFmt("%RTnaipv4", ipAddr);
2879 }
2880
2881 /* All parameters are set, create the new network. */
2882 hrc = virtualBox->CreateHostOnlyNetwork(bstrNetworkName.raw(), hostOnlyNetwork.asOutParam());
2883 if (FAILED(hrc))
2884 {
2885 LogRel(("NetworkAttachmentType_HostOnly: failed to create host-only network, hrc (0x%x)\n", hrc));
2886 H();
2887 }
2888 hrc = hostOnlyNetwork->COMSETTER(NetworkMask)(bstrNetworkMask.raw());
2889 if (FAILED(hrc))
2890 {
2891 LogRel(("NetworkAttachmentType_HostOnly: COMSETTER(NetworkMask) failed, hrc (0x%x)\n", hrc));
2892 H();
2893 }
2894 hrc = hostOnlyNetwork->COMSETTER(LowerIP)(bstrLowerIP.raw());
2895 if (FAILED(hrc))
2896 {
2897 LogRel(("NetworkAttachmentType_HostOnly: COMSETTER(LowerIP) failed, hrc (0x%x)\n", hrc));
2898 H();
2899 }
2900 hrc = hostOnlyNetwork->COMSETTER(UpperIP)(bstrUpperIP.raw());
2901 if (FAILED(hrc))
2902 {
2903 LogRel(("NetworkAttachmentType_HostOnly: COMSETTER(UpperIP) failed, hrc (0x%x)\n", hrc));
2904 H();
2905 }
2906 LogRel(("Console: created host-only network '%ls' with mask '%ls' and range '%ls'-'%ls'\n",
2907 bstrNetworkName.raw(), bstrNetworkMask.raw(), bstrLowerIP.raw(), bstrUpperIP.raw()));
2908 }
2909 else
2910 {
2911 /* The matching host-only network already exists. Tell the user to switch to it. */
2912 hrc = hostOnlyNetwork->COMGETTER(NetworkMask)(bstrNetworkMask.asOutParam());
2913 if (FAILED(hrc))
2914 {
2915 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(NetworkMask) failed, hrc (0x%x)\n", hrc));
2916 H();
2917 }
2918 hrc = hostOnlyNetwork->COMGETTER(LowerIP)(bstrLowerIP.asOutParam());
2919 if (FAILED(hrc))
2920 {
2921 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(LowerIP) failed, hrc (0x%x)\n", hrc));
2922 H();
2923 }
2924 hrc = hostOnlyNetwork->COMGETTER(UpperIP)(bstrUpperIP.asOutParam());
2925 if (FAILED(hrc))
2926 {
2927 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(UpperIP) failed, hrc (0x%x)\n", hrc));
2928 H();
2929 }
2930 }
2931 return pVMM->pfnVMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
2932 N_("Host-only adapters are no longer supported!\n"
2933 "For your convenience a host-only network named '%ls' has been "
2934 "created with network mask '%ls' and IP address range '%ls' - '%ls'.\n"
2935 "To fix this problem, switch to 'Host-only Network' "
2936 "attachment type in the VM settings.\n"),
2937 bstrNetworkName.raw(), bstrNetworkMask.raw(),
2938 bstrLowerIP.raw(), bstrUpperIP.raw());
2939#endif /* VBOX_WITH_VMNET */
2940 ComPtr<IHostNetworkInterface> hostInterface;
2941 hrc = host->FindHostNetworkInterfaceByName(HostOnlyName.raw(),
2942 hostInterface.asOutParam());
2943 if (!SUCCEEDED(hrc))
2944 {
2945 LogRel(("NetworkAttachmentType_HostOnly: FindByName failed, vrc=%Rrc\n", vrc));
2946 return pVMM->pfnVMR3SetError(pUVM, VERR_INTERNAL_ERROR, RT_SRC_POS,
2947 N_("Nonexistent host networking interface, name '%ls'"), HostOnlyName.raw());
2948 }
2949
2950 char szNetwork[INTNET_MAX_NETWORK_NAME];
2951 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszHostOnlyName);
2952
2953#if defined(RT_OS_WINDOWS)
2954# ifndef VBOX_WITH_NETFLT
2955 hrc = E_NOTIMPL;
2956 LogRel(("NetworkAttachmentType_HostOnly: Not Implemented\n"));
2957 H();
2958# else /* defined VBOX_WITH_NETFLT*/
2959 /** @todo r=bird: Put this in a function. */
2960
2961 HostNetworkInterfaceType_T eIfType;
2962 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
2963 if (FAILED(hrc))
2964 {
2965 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
2966 H();
2967 }
2968
2969 if (eIfType != HostNetworkInterfaceType_HostOnly)
2970 return pVMM->pfnVMR3SetError(pUVM, VERR_INTERNAL_ERROR, RT_SRC_POS,
2971 N_("Interface ('%ls') is not a Host-Only Adapter interface"),
2972 HostOnlyName.raw());
2973
2974 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
2975 if (FAILED(hrc))
2976 {
2977 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
2978 H();
2979 }
2980 Guid hostIFGuid(bstr);
2981
2982 INetCfg *pNc;
2983 ComPtr<INetCfgComponent> pAdaptorComponent;
2984 LPWSTR pszApp;
2985 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
2986 Assert(hrc == S_OK);
2987 if (hrc != S_OK)
2988 {
2989 LogRel(("NetworkAttachmentType_HostOnly: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
2990 H();
2991 }
2992
2993 /* get the adapter's INetCfgComponent*/
2994 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
2995 pAdaptorComponent.asOutParam());
2996 if (hrc != S_OK)
2997 {
2998 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
2999 LogRel(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n", hrc, hrc));
3000 H();
3001 }
3002# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
3003 char szTrunkName[INTNET_MAX_TRUNK_NAME];
3004 bool fNdis6 = false;
3005 wchar_t * pwszHelpText;
3006 hrc = pAdaptorComponent->GetHelpText(&pwszHelpText);
3007 Assert(hrc == S_OK);
3008 if (hrc == S_OK)
3009 {
3010 Log(("help-text=%ls\n", pwszHelpText));
3011 if (!wcscmp(pwszHelpText, L"VirtualBox NDIS 6.0 Miniport Driver"))
3012 fNdis6 = true;
3013 CoTaskMemFree(pwszHelpText);
3014 }
3015 if (fNdis6)
3016 {
3017 strncpy(szTrunkName, pszHostOnlyName, sizeof(szTrunkName) - 1);
3018 Log(("trunk=%s\n", szTrunkName));
3019 }
3020 else
3021 {
3022 char *pszTrunkName = szTrunkName;
3023 wchar_t * pswzBindName;
3024 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
3025 Assert(hrc == S_OK);
3026 if (hrc == S_OK)
3027 {
3028 int cwBindName = (int)wcslen(pswzBindName) + 1;
3029 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
3030 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
3031 {
3032 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
3033 pszTrunkName += cbFullBindNamePrefix-1;
3034 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
3035 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
3036 {
3037 DWORD err = GetLastError();
3038 hrc = HRESULT_FROM_WIN32(err);
3039 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
3040 hrc, hrc, err));
3041 }
3042 }
3043 else
3044 {
3045 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: insufficient szTrunkName buffer space\n"));
3046 /** @todo set appropriate error code */
3047 hrc = E_FAIL;
3048 }
3049
3050 if (hrc != S_OK)
3051 {
3052 AssertFailed();
3053 CoTaskMemFree(pswzBindName);
3054 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
3055 H();
3056 }
3057 }
3058 else
3059 {
3060 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
3061 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n",
3062 hrc, hrc));
3063 H();
3064 }
3065
3066
3067 CoTaskMemFree(pswzBindName);
3068 }
3069
3070 trunkType = TRUNKTYPE_NETADP;
3071 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
3072
3073 pAdaptorComponent.setNull();
3074 /* release the pNc finally */
3075 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
3076
3077 const char *pszTrunk = szTrunkName;
3078
3079 InsertConfigString(pCfg, "Trunk", pszTrunk);
3080 InsertConfigString(pCfg, "Network", szNetwork);
3081 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure); /** @todo why is this
3082 windows only?? */
3083 networkName = Bstr(szNetwork);
3084 trunkName = Bstr(pszTrunk);
3085# endif /* defined VBOX_WITH_NETFLT*/
3086#elif defined(RT_OS_DARWIN)
3087 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
3088 InsertConfigString(pCfg, "Network", szNetwork);
3089 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
3090 networkName = Bstr(szNetwork);
3091 trunkName = Bstr(pszHostOnlyName);
3092 trunkType = TRUNKTYPE_NETADP;
3093#else
3094 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
3095 InsertConfigString(pCfg, "Network", szNetwork);
3096 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
3097 networkName = Bstr(szNetwork);
3098 trunkName = Bstr(pszHostOnlyName);
3099 trunkType = TRUNKTYPE_NETFLT;
3100#endif
3101 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
3102
3103#if !defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
3104
3105 Bstr tmpAddr, tmpMask;
3106
3107 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPAddress",
3108 pszHostOnlyName).raw(),
3109 tmpAddr.asOutParam());
3110 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty())
3111 {
3112 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPNetMask",
3113 pszHostOnlyName).raw(),
3114 tmpMask.asOutParam());
3115 if (SUCCEEDED(hrc) && !tmpMask.isEmpty())
3116 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
3117 tmpMask.raw());
3118 else
3119 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
3120 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
3121 }
3122 else
3123 {
3124 /* Grab the IP number from the 'vboxnetX' instance number (see netif.h) */
3125 hrc = hostInterface->EnableStaticIPConfig(getDefaultIPv4Address(Bstr(pszHostOnlyName)).raw(),
3126 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
3127 }
3128
3129 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
3130
3131 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6Address",
3132 pszHostOnlyName).raw(),
3133 tmpAddr.asOutParam());
3134 if (SUCCEEDED(hrc))
3135 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6NetMask", pszHostOnlyName).raw(),
3136 tmpMask.asOutParam());
3137 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty() && !tmpMask.isEmpty())
3138 {
3139 hrc = hostInterface->EnableStaticIPConfigV6(tmpAddr.raw(),
3140 Utf8Str(tmpMask).toUInt32());
3141 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
3142 }
3143#endif
3144 break;
3145 }
3146
3147 case NetworkAttachmentType_Generic:
3148 {
3149 hrc = aNetworkAdapter->COMGETTER(GenericDriver)(bstr.asOutParam()); H();
3150 SafeArray<BSTR> names;
3151 SafeArray<BSTR> values;
3152 hrc = aNetworkAdapter->GetProperties(Bstr().raw(),
3153 ComSafeArrayAsOutParam(names),
3154 ComSafeArrayAsOutParam(values)); H();
3155
3156 InsertConfigString(pLunL0, "Driver", bstr);
3157 InsertConfigNode(pLunL0, "Config", &pCfg);
3158 for (size_t ii = 0; ii < names.size(); ++ii)
3159 {
3160 if (values[ii] && *values[ii])
3161 {
3162 Utf8Str const strName(names[ii]);
3163 Utf8Str const strValue(values[ii]);
3164 InsertConfigString(pCfg, strName.c_str(), strValue);
3165 }
3166 }
3167 break;
3168 }
3169
3170 case NetworkAttachmentType_NATNetwork:
3171 {
3172 hrc = aNetworkAdapter->COMGETTER(NATNetwork)(bstr.asOutParam()); H();
3173 if (!bstr.isEmpty())
3174 {
3175 /** @todo add intnet prefix to separate namespaces, and add trunk if dealing with vboxnatX */
3176 InsertConfigString(pLunL0, "Driver", "IntNet");
3177 InsertConfigNode(pLunL0, "Config", &pCfg);
3178 InsertConfigString(pCfg, "Network", bstr);
3179 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
3180 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
3181 networkName = bstr;
3182 trunkType = Bstr(TRUNKTYPE_WHATEVER);
3183 }
3184 break;
3185 }
3186
3187#ifdef VBOX_WITH_CLOUD_NET
3188 case NetworkAttachmentType_Cloud:
3189 {
3190 static const char *s_pszCloudExtPackName = VBOX_PUEL_PRODUCT;
3191 /*
3192 * Cloud network attachments do not work wihout installed extpack.
3193 * Without extpack support they won't work either.
3194 */
3195# ifdef VBOX_WITH_EXTPACK
3196 if ( !mptrExtPackManager->i_isExtPackUsable(s_pszCloudExtPackName)
3197 && !mptrExtPackManager->i_isExtPackUsable("Oracle VM VirtualBox Extension Pack")) /* Legacy name -- see @bugref{10690}. */
3198# endif
3199 {
3200 return pVMM->pfnVMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
3201 N_("Implementation of the cloud network attachment not found!\n"
3202 "To fix this problem, either install the '%s' or switch to "
3203 "another network attachment type in the VM settings."),
3204 s_pszCloudExtPackName);
3205 }
3206
3207 ComPtr<ICloudNetwork> network;
3208 hrc = aNetworkAdapter->COMGETTER(CloudNetwork)(bstr.asOutParam()); H();
3209 hrc = pMachine->COMGETTER(Name)(mGateway.mTargetVM.asOutParam()); H();
3210 hrc = virtualBox->FindCloudNetworkByName(bstr.raw(), network.asOutParam()); H();
3211 hrc = generateKeys(mGateway);
3212 if (FAILED(hrc))
3213 {
3214 if (hrc == E_NOTIMPL)
3215 return pVMM->pfnVMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
3216 N_("Failed to generate a key pair due to missing libssh\n"
3217 "To fix this problem, either build VirtualBox with libssh "
3218 "support or switch to another network attachment type in "
3219 "the VM settings."));
3220 return pVMM->pfnVMR3SetError(pUVM, VERR_INTERNAL_ERROR, RT_SRC_POS,
3221 N_("Failed to generate a key pair due to libssh error!"));
3222 }
3223 hrc = startCloudGateway(virtualBox, network, mGateway);
3224 if (FAILED(hrc))
3225 {
3226 if (hrc == VBOX_E_OBJECT_NOT_FOUND)
3227 return pVMM->pfnVMR3SetError(pUVM, hrc, RT_SRC_POS,
3228 N_("Failed to start cloud gateway instance.\nCould not find suitable "
3229 "standard cloud images. Make sure you ran 'VBoxManage cloud network setup' "
3230 "with correct '--gateway-os-name' and '--gateway-os-version' parameters. "
3231 "Check VBoxSVC.log for actual values used to look up cloud images."));
3232 return pVMM->pfnVMR3SetError(pUVM, hrc, RT_SRC_POS,
3233 N_("Failed to start cloud gateway instance.\nMake sure you set up "
3234 "cloud networking properly with 'VBoxManage cloud network setup'. "
3235 "Check VBoxSVC.log for details."));
3236 }
3237 InsertConfigBytes(pDevCfg, "MAC", &mGateway.mCloudMacAddress, sizeof(mGateway.mCloudMacAddress));
3238 if (!bstr.isEmpty())
3239 {
3240 InsertConfigString(pLunL0, "Driver", "CloudTunnel");
3241 InsertConfigNode(pLunL0, "Config", &pCfg);
3242 InsertConfigPassword(pCfg, "SshKey", mGateway.mPrivateSshKey);
3243 InsertConfigString(pCfg, "PrimaryIP", mGateway.mCloudPublicIp);
3244 InsertConfigString(pCfg, "SecondaryIP", mGateway.mCloudSecondaryPublicIp);
3245 InsertConfigBytes(pCfg, "TargetMAC", &mGateway.mLocalMacAddress, sizeof(mGateway.mLocalMacAddress));
3246 hrc = i_configProxy(virtualBox, pCfg, "Primary", mGateway.mCloudPublicIp);
3247 if (FAILED(hrc))
3248 {
3249 return pVMM->pfnVMR3SetError(pUVM, hrc, RT_SRC_POS,
3250 N_("Failed to configure proxy for accessing cloud gateway instance via primary VNIC.\n"
3251 "Check VirtualBox.log for details."));
3252 }
3253 hrc = i_configProxy(virtualBox, pCfg, "Secondary", mGateway.mCloudSecondaryPublicIp);
3254 if (FAILED(hrc))
3255 {
3256 return pVMM->pfnVMR3SetError(pUVM, hrc, RT_SRC_POS,
3257 N_("Failed to configure proxy for accessing cloud gateway instance via secondary VNIC.\n"
3258 "Check VirtualBox.log for details."));
3259 }
3260 networkName = bstr;
3261 trunkType = Bstr(TRUNKTYPE_WHATEVER);
3262 }
3263 break;
3264 }
3265#endif /* VBOX_WITH_CLOUD_NET */
3266
3267#ifdef VBOX_WITH_VMNET
3268 case NetworkAttachmentType_HostOnlyNetwork:
3269 {
3270 Bstr bstrId, bstrNetMask, bstrLowerIP, bstrUpperIP;
3271 ComPtr<IHostOnlyNetwork> network;
3272 hrc = aNetworkAdapter->COMGETTER(HostOnlyNetwork)(bstr.asOutParam()); H();
3273 hrc = virtualBox->FindHostOnlyNetworkByName(bstr.raw(), network.asOutParam());
3274 if (FAILED(hrc))
3275 {
3276 LogRel(("NetworkAttachmentType_HostOnlyNetwork: FindByName failed, hrc (0x%x)\n", hrc));
3277 return pVMM->pfnVMR3SetError(pUVM, VERR_INTERNAL_ERROR, RT_SRC_POS,
3278 N_("Nonexistent host-only network '%ls'"), bstr.raw());
3279 }
3280 hrc = network->COMGETTER(Id)(bstrId.asOutParam()); H();
3281 hrc = network->COMGETTER(NetworkMask)(bstrNetMask.asOutParam()); H();
3282 hrc = network->COMGETTER(LowerIP)(bstrLowerIP.asOutParam()); H();
3283 hrc = network->COMGETTER(UpperIP)(bstrUpperIP.asOutParam()); H();
3284 if (!bstr.isEmpty())
3285 {
3286 InsertConfigString(pLunL0, "Driver", "VMNet");
3287 InsertConfigNode(pLunL0, "Config", &pCfg);
3288 // InsertConfigString(pCfg, "Trunk", bstr);
3289 // InsertConfigStringF(pCfg, "Network", "HostOnlyNetworking-%ls", bstr.raw());
3290 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
3291 InsertConfigString(pCfg, "Id", bstrId);
3292 InsertConfigString(pCfg, "NetworkMask", bstrNetMask);
3293 InsertConfigString(pCfg, "LowerIP", bstrLowerIP);
3294 InsertConfigString(pCfg, "UpperIP", bstrUpperIP);
3295 // InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
3296 networkName.setNull(); // We do not want DHCP server on our network!
3297 // trunkType = Bstr(TRUNKTYPE_WHATEVER);
3298 }
3299 break;
3300 }
3301#endif /* VBOX_WITH_VMNET */
3302
3303 default:
3304 AssertMsgFailed(("should not get here!\n"));
3305 break;
3306 }
3307
3308 /*
3309 * Attempt to attach the driver.
3310 */
3311 switch (eAttachmentType)
3312 {
3313 case NetworkAttachmentType_Null:
3314 break;
3315
3316 case NetworkAttachmentType_Bridged:
3317 case NetworkAttachmentType_Internal:
3318 case NetworkAttachmentType_HostOnly:
3319#ifdef VBOX_WITH_VMNET
3320 case NetworkAttachmentType_HostOnlyNetwork:
3321#endif /* VBOX_WITH_VMNET */
3322 case NetworkAttachmentType_NAT:
3323 case NetworkAttachmentType_Generic:
3324 case NetworkAttachmentType_NATNetwork:
3325#ifdef VBOX_WITH_CLOUD_NET
3326 case NetworkAttachmentType_Cloud:
3327#endif /* VBOX_WITH_CLOUD_NET */
3328 {
3329 if (SUCCEEDED(hrc) && RT_SUCCESS(vrc))
3330 {
3331 if (fAttachDetach)
3332 {
3333 vrc = pVMM->pfnPDMR3DriverAttach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/, NULL /* ppBase */);
3334 if (RT_FAILURE(vrc))
3335 LogRel(("Console::i_configNetwork: Error attaching device '%s' (instance %u) to LUN %u, rc=%Rrc\n",
3336 pszDevice, uInstance, uLun, vrc));
3337 }
3338
3339 {
3340 /** @todo pritesh: get the dhcp server name from the
3341 * previous network configuration and then stop the server
3342 * else it may conflict with the dhcp server running with
3343 * the current attachment type
3344 */
3345 /* Stop the hostonly DHCP Server */
3346 }
3347
3348 /*
3349 * NAT networks start their DHCP server theirself, see NATNetwork::Start()
3350 */
3351 if ( !networkName.isEmpty()
3352 && eAttachmentType != NetworkAttachmentType_NATNetwork)
3353 {
3354 /*
3355 * Until we implement service reference counters DHCP Server will be stopped
3356 * by DHCPServerRunner destructor.
3357 */
3358 ComPtr<IDHCPServer> dhcpServer;
3359 hrc = virtualBox->FindDHCPServerByNetworkName(networkName.raw(), dhcpServer.asOutParam());
3360 if (SUCCEEDED(hrc))
3361 {
3362 /* there is a DHCP server available for this network */
3363 BOOL fEnabledDhcp;
3364 hrc = dhcpServer->COMGETTER(Enabled)(&fEnabledDhcp);
3365 if (FAILED(hrc))
3366 {
3367 LogRel(("DHCP svr: COMGETTER(Enabled) failed, hrc (%Rhrc)\n", hrc));
3368 H();
3369 }
3370
3371 if (fEnabledDhcp)
3372 dhcpServer->Start(trunkName.raw(), trunkType.raw());
3373 }
3374 else
3375 hrc = S_OK;
3376 }
3377 }
3378
3379 break;
3380 }
3381
3382 default:
3383 AssertMsgFailed(("should not get here!\n"));
3384 break;
3385 }
3386
3387 meAttachmentType[uInstance] = eAttachmentType;
3388 }
3389 catch (ConfigError &x)
3390 {
3391 // InsertConfig threw something:
3392 return x.m_vrc;
3393 }
3394
3395#undef H
3396
3397 return VINF_SUCCESS;
3398}
3399
3400
3401/**
3402 * Configures the serial port at the given CFGM node with the supplied parameters.
3403 *
3404 * @returns VBox status code.
3405 * @param pInst The instance CFGM node.
3406 * @param ePortMode The port mode to sue.
3407 * @param pszPath The serial port path.
3408 * @param fServer Flag whether the port should act as a server
3409 * for the pipe and TCP mode or connect as a client.
3410 */
3411int Console::i_configSerialPort(PCFGMNODE pInst, PortMode_T ePortMode, const char *pszPath, bool fServer)
3412{
3413 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
3414 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */
3415 PCFGMNODE pLunL1Cfg = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/Config */
3416
3417 try
3418 {
3419 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3420 if (ePortMode == PortMode_HostPipe)
3421 {
3422 InsertConfigString(pLunL0, "Driver", "Char");
3423 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
3424 InsertConfigString(pLunL1, "Driver", "NamedPipe");
3425 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
3426 InsertConfigString(pLunL1Cfg, "Location", pszPath);
3427 InsertConfigInteger(pLunL1Cfg, "IsServer", fServer);
3428 }
3429 else if (ePortMode == PortMode_HostDevice)
3430 {
3431 InsertConfigString(pLunL0, "Driver", "Host Serial");
3432 InsertConfigNode(pLunL0, "Config", &pLunL1);
3433 InsertConfigString(pLunL1, "DevicePath", pszPath);
3434 }
3435 else if (ePortMode == PortMode_TCP)
3436 {
3437 InsertConfigString(pLunL0, "Driver", "Char");
3438 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
3439 InsertConfigString(pLunL1, "Driver", "TCP");
3440 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
3441 InsertConfigString(pLunL1Cfg, "Location", pszPath);
3442 InsertConfigInteger(pLunL1Cfg, "IsServer", fServer);
3443 }
3444 else if (ePortMode == PortMode_RawFile)
3445 {
3446 InsertConfigString(pLunL0, "Driver", "Char");
3447 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
3448 InsertConfigString(pLunL1, "Driver", "RawFile");
3449 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
3450 InsertConfigString(pLunL1Cfg, "Location", pszPath);
3451 }
3452 }
3453 catch (ConfigError &x)
3454 {
3455 /* InsertConfig threw something */
3456 return x.m_vrc;
3457 }
3458
3459 return VINF_SUCCESS;
3460}
3461
3462
3463#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
3464#define VRC() AssertLogRelMsgReturn(RT_SUCCESS(vrc), ("vrc=%Rrc\n", vrc), vrc)
3465
3466int Console::i_configPdm(ComPtr<IMachine> pMachine, PCVMMR3VTABLE pVMM, PUVM pUVM, PCFGMNODE pRoot)
3467{
3468 PCFGMNODE pPDM;
3469 PCFGMNODE pNode;
3470 PCFGMNODE pMod;
3471 InsertConfigNode(pRoot, "PDM", &pPDM);
3472 InsertConfigNode(pPDM, "Devices", &pNode);
3473 InsertConfigNode(pPDM, "Drivers", &pNode);
3474 InsertConfigNode(pNode, "VBoxC", &pMod);
3475#ifdef VBOX_WITH_XPCOM
3476 // VBoxC is located in the components subdirectory
3477 char szPathVBoxC[RTPATH_MAX];
3478 int vrc = RTPathAppPrivateArch(szPathVBoxC, RTPATH_MAX); VRC();
3479 vrc = RTPathAppend(szPathVBoxC, RTPATH_MAX, "/components/VBoxC"); VRC();
3480 InsertConfigString(pMod, "Path", szPathVBoxC);
3481#else
3482 InsertConfigString(pMod, "Path", "VBoxC");
3483#endif
3484
3485
3486 /*
3487 * Block cache settings.
3488 */
3489 PCFGMNODE pPDMBlkCache;
3490 InsertConfigNode(pPDM, "BlkCache", &pPDMBlkCache);
3491
3492 /* I/O cache size */
3493 ULONG ioCacheSize = 5;
3494 HRESULT hrc = pMachine->COMGETTER(IOCacheSize)(&ioCacheSize); H();
3495 InsertConfigInteger(pPDMBlkCache, "CacheSize", ioCacheSize * _1M);
3496
3497 /*
3498 * Bandwidth groups.
3499 */
3500 ComPtr<IBandwidthControl> bwCtrl;
3501
3502 hrc = pMachine->COMGETTER(BandwidthControl)(bwCtrl.asOutParam()); H();
3503
3504 com::SafeIfaceArray<IBandwidthGroup> bwGroups;
3505 hrc = bwCtrl->GetAllBandwidthGroups(ComSafeArrayAsOutParam(bwGroups)); H();
3506
3507 PCFGMNODE pAc;
3508 InsertConfigNode(pPDM, "AsyncCompletion", &pAc);
3509 PCFGMNODE pAcFile;
3510 InsertConfigNode(pAc, "File", &pAcFile);
3511 PCFGMNODE pAcFileBwGroups;
3512 InsertConfigNode(pAcFile, "BwGroups", &pAcFileBwGroups);
3513#ifdef VBOX_WITH_NETSHAPER
3514 PCFGMNODE pNetworkShaper;
3515 InsertConfigNode(pPDM, "NetworkShaper", &pNetworkShaper);
3516 PCFGMNODE pNetworkBwGroups;
3517 InsertConfigNode(pNetworkShaper, "BwGroups", &pNetworkBwGroups);
3518#endif /* VBOX_WITH_NETSHAPER */
3519
3520 for (size_t i = 0; i < bwGroups.size(); i++)
3521 {
3522 Bstr strName;
3523 hrc = bwGroups[i]->COMGETTER(Name)(strName.asOutParam()); H();
3524 if (strName.isEmpty())
3525 return pVMM->pfnVMR3SetError(pUVM, VERR_CFGM_NO_NODE, RT_SRC_POS, N_("No bandwidth group name specified"));
3526
3527 BandwidthGroupType_T enmType = BandwidthGroupType_Null;
3528 hrc = bwGroups[i]->COMGETTER(Type)(&enmType); H();
3529 LONG64 cMaxBytesPerSec = 0;
3530 hrc = bwGroups[i]->COMGETTER(MaxBytesPerSec)(&cMaxBytesPerSec); H();
3531
3532 if (enmType == BandwidthGroupType_Disk)
3533 {
3534 PCFGMNODE pBwGroup;
3535 InsertConfigNode(pAcFileBwGroups, Utf8Str(strName).c_str(), &pBwGroup);
3536 InsertConfigInteger(pBwGroup, "Max", cMaxBytesPerSec);
3537 InsertConfigInteger(pBwGroup, "Start", cMaxBytesPerSec);
3538 InsertConfigInteger(pBwGroup, "Step", 0);
3539 }
3540#ifdef VBOX_WITH_NETSHAPER
3541 else if (enmType == BandwidthGroupType_Network)
3542 {
3543 /* Network bandwidth groups. */
3544 PCFGMNODE pBwGroup;
3545 InsertConfigNode(pNetworkBwGroups, Utf8Str(strName).c_str(), &pBwGroup);
3546 InsertConfigInteger(pBwGroup, "Max", cMaxBytesPerSec);
3547 }
3548#endif /* VBOX_WITH_NETSHAPER */
3549 }
3550
3551 /** @todo r=aeichner Looks like this setting is completely unused in VMM/PDM. */
3552 BOOL fAllowTracingToAccessVM;
3553 hrc = pMachine->COMGETTER(AllowTracingToAccessVM)(&fAllowTracingToAccessVM); H();
3554 if (fAllowTracingToAccessVM)
3555 InsertConfigInteger(pPDM, "AllowTracingToAccessVM", 1);
3556
3557 return VINF_SUCCESS;
3558}
3559
3560
3561int Console::i_configAudioCtrl(ComPtr<IVirtualBox> pVBox, ComPtr<IMachine> pMachine, BusAssignmentManager *pBusMgr, PCFGMNODE pDevices,
3562 bool fOsXGuest, bool *pfAudioEnabled)
3563{
3564 Utf8Str strTmp;
3565 PCFGMNODE pDev = NULL; /* /Devices/Dev/ */
3566 PCFGMNODE pInst = NULL; /* /Devices/Dev/0/ */
3567 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
3568 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
3569
3570 /*
3571 * AC'97 ICH / SoundBlaster16 audio / Intel HD Audio.
3572 */
3573 ComPtr<IAudioSettings> audioSettings;
3574 HRESULT hrc = pMachine->COMGETTER(AudioSettings)(audioSettings.asOutParam()); H();
3575
3576 BOOL fAudioEnabled = FALSE;
3577 ComPtr<IAudioAdapter> audioAdapter;
3578 hrc = audioSettings->COMGETTER(Adapter)(audioAdapter.asOutParam()); H();
3579 if (audioAdapter)
3580 {
3581 hrc = audioAdapter->COMGETTER(Enabled)(&fAudioEnabled); H();
3582 }
3583
3584 if (fAudioEnabled)
3585 {
3586 *pfAudioEnabled = true;
3587
3588 AudioControllerType_T enmAudioController;
3589 hrc = audioAdapter->COMGETTER(AudioController)(&enmAudioController); H();
3590 AudioCodecType_T enmAudioCodec;
3591 hrc = audioAdapter->COMGETTER(AudioCodec)(&enmAudioCodec); H();
3592
3593 GetExtraDataBoth(pVBox, pMachine, "VBoxInternal2/Audio/Device/TimerHz", &strTmp);
3594 const uint64_t uTimerHz = strTmp.toUInt64();
3595
3596 GetExtraDataBoth(pVBox, pMachine, "VBoxInternal2/Audio/Device/BufSizeInMs", &strTmp);
3597 const uint64_t uBufSizeInMs = strTmp.toUInt64();
3598
3599 GetExtraDataBoth(pVBox, pMachine, "VBoxInternal2/Audio/Device/BufSizeOutMs", &strTmp);
3600 const uint64_t uBufSizeOutMs = strTmp.toUInt64();
3601
3602 GetExtraDataBoth(pVBox, pMachine, "VBoxInternal2/Audio/Debug/Enabled", &strTmp);
3603 const bool fDebugEnabled = strTmp.equalsIgnoreCase("true") || strTmp.equalsIgnoreCase("1");
3604
3605 GetExtraDataBoth(pVBox, pMachine, "VBoxInternal2/Audio/Debug/Level", &strTmp);
3606 const uint32_t uDebugLevel = strTmp.toUInt32();
3607
3608 Utf8Str strDebugPathOut;
3609 GetExtraDataBoth(pVBox, pMachine, "VBoxInternal2/Audio/Debug/PathOut", &strDebugPathOut);
3610
3611#ifdef VBOX_WITH_AUDIO_VALIDATIONKIT
3612 GetExtraDataBoth(pVBox, pMachine, "VBoxInternal2/Audio/VaKit/Enabled", &strTmp); /* Deprecated; do not use! */
3613 if (strTmp.isEmpty())
3614 GetExtraDataBoth(pVBox, pMachine, "VBoxInternal2/Audio/ValKit/Enabled", &strTmp);
3615 /* Whether the Validation Kit audio backend runs as the primary backend.
3616 * Can also be used with VBox release builds. */
3617 const bool fValKitEnabled = strTmp.equalsIgnoreCase("true") || strTmp.equalsIgnoreCase("1");
3618#endif
3619 /** @todo Implement an audio device class, similar to the audio backend class, to construct the common stuff
3620 * without duplicating (more) code. */
3621
3622 const char *pszAudioDevice;
3623 switch (enmAudioController)
3624 {
3625 case AudioControllerType_AC97:
3626 {
3627 /* ICH AC'97. */
3628 pszAudioDevice = "ichac97";
3629
3630 InsertConfigNode(pDevices, pszAudioDevice, &pDev);
3631 InsertConfigNode(pDev, "0", &pInst);
3632 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3633 hrc = pBusMgr->assignPCIDevice(pszAudioDevice, pInst); H();
3634 InsertConfigNode(pInst, "Config", &pCfg);
3635 switch (enmAudioCodec)
3636 {
3637 case AudioCodecType_STAC9700:
3638 InsertConfigString(pCfg, "Codec", "STAC9700");
3639 break;
3640 case AudioCodecType_AD1980:
3641 InsertConfigString(pCfg, "Codec", "AD1980");
3642 break;
3643 default: AssertFailedBreak();
3644 }
3645 if (uTimerHz)
3646 InsertConfigInteger(pCfg, "TimerHz", uTimerHz);
3647 if (uBufSizeInMs)
3648 InsertConfigInteger(pCfg, "BufSizeInMs", uBufSizeInMs);
3649 if (uBufSizeOutMs)
3650 InsertConfigInteger(pCfg, "BufSizeOutMs", uBufSizeOutMs);
3651 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
3652 if (strDebugPathOut.isNotEmpty())
3653 InsertConfigString(pCfg, "DebugPathOut", strDebugPathOut);
3654 break;
3655 }
3656 case AudioControllerType_SB16:
3657 {
3658 /* Legacy SoundBlaster16. */
3659 pszAudioDevice = "sb16";
3660
3661 InsertConfigNode(pDevices, pszAudioDevice, &pDev);
3662 InsertConfigNode(pDev, "0", &pInst);
3663 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3664 InsertConfigNode(pInst, "Config", &pCfg);
3665 InsertConfigInteger(pCfg, "IRQ", 5);
3666 InsertConfigInteger(pCfg, "DMA", 1);
3667 InsertConfigInteger(pCfg, "DMA16", 5);
3668 InsertConfigInteger(pCfg, "Port", 0x220);
3669 InsertConfigInteger(pCfg, "Version", 0x0405);
3670 if (uTimerHz)
3671 InsertConfigInteger(pCfg, "TimerHz", uTimerHz);
3672 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
3673 if (strDebugPathOut.isNotEmpty())
3674 InsertConfigString(pCfg, "DebugPathOut", strDebugPathOut);
3675 break;
3676 }
3677 case AudioControllerType_HDA:
3678 {
3679 /* Intel HD Audio. */
3680 pszAudioDevice = "hda";
3681
3682 InsertConfigNode(pDevices, pszAudioDevice, &pDev);
3683 InsertConfigNode(pDev, "0", &pInst);
3684 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3685 hrc = pBusMgr->assignPCIDevice(pszAudioDevice, pInst); H();
3686 InsertConfigNode(pInst, "Config", &pCfg);
3687 if (uBufSizeInMs)
3688 InsertConfigInteger(pCfg, "BufSizeInMs", uBufSizeInMs);
3689 if (uBufSizeOutMs)
3690 InsertConfigInteger(pCfg, "BufSizeOutMs", uBufSizeOutMs);
3691 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
3692 if (strDebugPathOut.isNotEmpty())
3693 InsertConfigString(pCfg, "DebugPathOut", strDebugPathOut);
3694
3695 /* macOS guests uses a different HDA variant to make 10.14+ (or maybe 10.13?) recognize the device. */
3696 if (fOsXGuest)
3697 InsertConfigString(pCfg, "DeviceName", "Intel Sunrise Point");
3698 break;
3699 }
3700 default:
3701 pszAudioDevice = "oops";
3702 AssertFailedBreak();
3703 }
3704
3705 PCFGMNODE pCfgAudioAdapter = NULL;
3706 InsertConfigNode(pInst, "AudioConfig", &pCfgAudioAdapter);
3707 SafeArray<BSTR> audioProps;
3708 hrc = audioAdapter->COMGETTER(PropertiesList)(ComSafeArrayAsOutParam(audioProps)); H();
3709 if (SUCCEEDED(hrc))
3710 {
3711 std::list<Utf8Str> audioPropertyNamesList;
3712 for (size_t i = 0; i < audioProps.size(); ++i)
3713 {
3714 Bstr bstrValue;
3715 audioPropertyNamesList.push_back(Utf8Str(audioProps[i]));
3716 hrc = audioAdapter->GetProperty(audioProps[i], bstrValue.asOutParam());
3717 if (SUCCEEDED(hrc))
3718 {
3719 Utf8Str strKey(audioProps[i]);
3720 InsertConfigString(pCfgAudioAdapter, strKey.c_str(), bstrValue);
3721 }
3722 }
3723 }
3724
3725 /*
3726 * The audio driver.
3727 */
3728 const char *pszAudioDriver = NULL;
3729#ifdef VBOX_WITH_AUDIO_VALIDATIONKIT
3730 if (fValKitEnabled)
3731 {
3732 pszAudioDriver = "ValidationKitAudio";
3733 LogRel(("Audio: ValidationKit driver active\n"));
3734 }
3735#endif
3736 /* If nothing else was selected before, ask the API. */
3737 if (pszAudioDriver == NULL)
3738 {
3739 AudioDriverType_T enmAudioDriver;
3740 hrc = audioAdapter->COMGETTER(AudioDriver)(&enmAudioDriver); H();
3741
3742 /* The "Default" audio driver needs special treatment, as we need to figure out which driver to use
3743 * by default on the current platform. */
3744 bool const fUseDefaultDrv = enmAudioDriver == AudioDriverType_Default;
3745
3746 AudioDriverType_T const enmDefaultAudioDriver = settings::MachineConfigFile::getHostDefaultAudioDriver();
3747
3748 if (fUseDefaultDrv)
3749 {
3750 enmAudioDriver = enmDefaultAudioDriver;
3751 if (enmAudioDriver == AudioDriverType_Null)
3752 LogRel(("Audio: Warning: No default driver detected for current platform -- defaulting to Null audio backend\n"));
3753 }
3754
3755 switch (enmAudioDriver)
3756 {
3757 case AudioDriverType_Default: /* Can't happen, but handle it anyway. */
3758 RT_FALL_THROUGH();
3759 case AudioDriverType_Null:
3760 pszAudioDriver = "NullAudio";
3761 break;
3762#ifdef RT_OS_WINDOWS
3763# ifdef VBOX_WITH_WINMM
3764 case AudioDriverType_WinMM:
3765# error "Port WinMM audio backend!" /** @todo Still needed? */
3766 break;
3767# endif
3768 case AudioDriverType_DirectSound:
3769 /* Use the Windows Audio Session (WAS) API rather than Direct Sound on Windows
3770 versions we've tested it on (currently W7+). Since Vista, Direct Sound has
3771 been emulated on top of WAS according to the docs, so better use WAS directly.
3772
3773 Set extradata value "VBoxInternal2/Audio/WindowsDrv" "dsound" to no use WasAPI.
3774
3775 Keep this hack for backwards compatibility (introduced < 7.0).
3776 */
3777 GetExtraDataBoth(pVBox, pMachine, "VBoxInternal2/Audio/WindowsDrv", &strTmp); H();
3778 if ( enmDefaultAudioDriver == AudioDriverType_WAS
3779 && ( strTmp.isEmpty()
3780 || strTmp.equalsIgnoreCase("was")
3781 || strTmp.equalsIgnoreCase("wasapi")) )
3782 {
3783 /* Nothing to do here, fall through to WAS driver. */
3784 LogRel(("Audio: Using Windows Audio Session (WAS) backend instead of DirectSound for performance reasons\n"));
3785 }
3786 else
3787 {
3788 pszAudioDriver = "DSoundAudio";
3789 break;
3790 }
3791 RT_FALL_THROUGH();
3792 case AudioDriverType_WAS:
3793 if (enmDefaultAudioDriver == AudioDriverType_WAS) /* WAS supported? */
3794 pszAudioDriver = "HostAudioWas";
3795 else if (enmDefaultAudioDriver == AudioDriverType_DirectSound)
3796 {
3797 LogRel(("Audio: Warning: Windows Audio Session (WAS) not supported, defaulting to DirectSound backend\n"));
3798 pszAudioDriver = "DSoundAudio";
3799 }
3800 break;
3801#endif /* RT_OS_WINDOWS */
3802#ifdef RT_OS_SOLARIS
3803 case AudioDriverType_SolAudio:
3804 /* Should not happen, as the Solaris Audio backend is not around anymore.
3805 * Remove this sometime later. */
3806 LogRel(("Audio: Warning: Solaris Audio is deprecated, please switch to OSS!\n"));
3807 LogRel(("Audio: Automatically setting host audio backend to OSS\n"));
3808
3809 /* Manually set backend to OSS for now. */
3810 pszAudioDriver = "OSSAudio";
3811 break;
3812#endif
3813#ifdef VBOX_WITH_AUDIO_OSS
3814 case AudioDriverType_OSS:
3815 pszAudioDriver = "OSSAudio";
3816 break;
3817#endif
3818#ifdef VBOX_WITH_AUDIO_ALSA
3819 case AudioDriverType_ALSA:
3820 pszAudioDriver = "ALSAAudio";
3821 break;
3822#endif
3823#ifdef VBOX_WITH_AUDIO_PULSE
3824 case AudioDriverType_Pulse:
3825 pszAudioDriver = "PulseAudio";
3826 break;
3827#endif
3828#ifdef RT_OS_DARWIN
3829 case AudioDriverType_CoreAudio:
3830 pszAudioDriver = "CoreAudio";
3831 break;
3832#endif
3833 default:
3834 pszAudioDriver = "oops";
3835 AssertFailedBreak();
3836 }
3837
3838 if (fUseDefaultDrv)
3839 LogRel(("Audio: Detected default audio driver type is '%s'\n", pszAudioDriver));
3840 }
3841
3842 BOOL fAudioEnabledIn = FALSE;
3843 hrc = audioAdapter->COMGETTER(EnabledIn)(&fAudioEnabledIn); H();
3844 BOOL fAudioEnabledOut = FALSE;
3845 hrc = audioAdapter->COMGETTER(EnabledOut)(&fAudioEnabledOut); H();
3846
3847 unsigned idxAudioLun = 0;
3848
3849 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", idxAudioLun);
3850 i_configAudioDriver(pVBox, pMachine, pLunL0, pszAudioDriver, !!fAudioEnabledIn, !!fAudioEnabledOut);
3851 idxAudioLun++;
3852
3853#ifdef VBOX_WITH_AUDIO_VRDE
3854 /* Insert dummy audio driver to have the LUN configured. */
3855 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", idxAudioLun);
3856 InsertConfigString(pLunL0, "Driver", "AUDIO");
3857 {
3858 AudioDriverCfg DrvCfgVRDE(pszAudioDevice, 0 /* Instance */, idxAudioLun, "AudioVRDE",
3859 !!fAudioEnabledIn, !!fAudioEnabledOut);
3860 int vrc = mAudioVRDE->InitializeConfig(&DrvCfgVRDE);
3861 AssertRCStmt(vrc, throw ConfigError(__FUNCTION__, vrc, "mAudioVRDE->InitializeConfig failed"));
3862 }
3863 idxAudioLun++;
3864#endif
3865
3866#ifdef VBOX_WITH_AUDIO_RECORDING
3867 /* Insert dummy audio driver to have the LUN configured. */
3868 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", idxAudioLun);
3869 InsertConfigString(pLunL0, "Driver", "AUDIO");
3870 {
3871 AudioDriverCfg DrvCfgVideoRec(pszAudioDevice, 0 /* Instance */, idxAudioLun, "AudioVideoRec",
3872 false /*a_fEnabledIn*/, true /*a_fEnabledOut*/);
3873 int vrc = mRecording.mAudioRec->InitializeConfig(&DrvCfgVideoRec);
3874 AssertRCStmt(vrc, throw ConfigError(__FUNCTION__, vrc, "Recording.mAudioRec->InitializeConfig failed"));
3875 }
3876 idxAudioLun++;
3877#endif
3878
3879 if (fDebugEnabled)
3880 {
3881#ifdef VBOX_WITH_AUDIO_DEBUG
3882# ifdef VBOX_WITH_AUDIO_VALIDATIONKIT
3883 /*
3884 * When both, ValidationKit and Debug mode (for audio) are enabled,
3885 * skip configuring the Debug audio driver, as both modes can
3886 * mess with the audio data and would lead to side effects.
3887 *
3888 * The ValidationKit audio driver has precedence over the Debug audio driver.
3889 *
3890 * This also can (and will) be used in VBox release builds.
3891 */
3892 if (fValKitEnabled)
3893 {
3894 LogRel(("Audio: Warning: ValidationKit running and Debug mode enabled -- disabling Debug driver\n"));
3895 }
3896 else /* Debug mode active -- run both (nice for catching errors / doing development). */
3897 {
3898 /*
3899 * The ValidationKit backend.
3900 */
3901 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", idxAudioLun);
3902 i_configAudioDriver(pVBox, pMachine, pLunL0, "ValidationKitAudio",
3903 !!fAudioEnabledIn, !!fAudioEnabledOut);
3904 idxAudioLun++;
3905# endif /* VBOX_WITH_AUDIO_VALIDATIONKIT */
3906 /*
3907 * The Debug audio backend.
3908 */
3909 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", idxAudioLun);
3910 i_configAudioDriver(pVBox, pMachine, pLunL0, "DebugAudio",
3911 !!fAudioEnabledIn, !!fAudioEnabledOut);
3912 idxAudioLun++;
3913# ifdef VBOX_WITH_AUDIO_VALIDATIONKIT
3914 }
3915# endif /* VBOX_WITH_AUDIO_VALIDATIONKIT */
3916#endif /* VBOX_WITH_AUDIO_DEBUG */
3917
3918 /*
3919 * Tweak the logging groups.
3920 */
3921 Utf8Str strGroups("drv_audio.e.l.l2.l3.f"
3922 " audio_mixer.e.l.l2.l3.f"
3923 " dev_hda_codec.e.l.l2.l3.f"
3924 " dev_hda.e.l.l2.l3.f"
3925 " dev_ac97.e.l.l2.l3.f"
3926 " dev_sb16.e.l.l2.l3.f");
3927
3928 LogRel(("Audio: Debug level set to %RU32\n", uDebugLevel));
3929
3930 switch (uDebugLevel)
3931 {
3932 case 0:
3933 strGroups += " drv_host_audio.e.l.l2.l3.f";
3934 break;
3935 case 1:
3936 RT_FALL_THROUGH();
3937 case 2:
3938 RT_FALL_THROUGH();
3939 case 3:
3940 strGroups += " drv_host_audio.e.l.l2.l3.f+audio_test.e.l.l2.l3.f";
3941 break;
3942 case 4:
3943 RT_FALL_THROUGH();
3944 default:
3945 strGroups += " drv_host_audio.e.l.l2.l3.l4.f+audio_test.e.l.l2.l3.l4.f";
3946 break;
3947 }
3948
3949 int vrc = RTLogGroupSettings(RTLogRelGetDefaultInstance(), strGroups.c_str());
3950 if (RT_FAILURE(vrc))
3951 LogRel(("Audio: Setting debug logging failed, vrc=%Rrc\n", vrc));
3952 }
3953 }
3954
3955 return VINF_SUCCESS;
3956}
3957
3958
3959int Console::i_configVmmDev(ComPtr<IMachine> pMachine, BusAssignmentManager *pBusMgr, PCFGMNODE pDevices, bool fMmioReq)
3960{
3961 VMMDev *pVMMDev = m_pVMMDev; Assert(pVMMDev);
3962
3963 int vrc = VINF_SUCCESS;
3964 PCFGMNODE pDev = NULL; /* /Devices/Dev/ */
3965 PCFGMNODE pInst = NULL; /* /Devices/Dev/0/ */
3966 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
3967 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
3968
3969 /*
3970 * VMM Device
3971 */
3972 InsertConfigNode(pDevices, "VMMDev", &pDev);
3973 InsertConfigNode(pDev, "0", &pInst);
3974 InsertConfigNode(pInst, "Config", &pCfg);
3975 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3976 HRESULT hrc = pBusMgr->assignPCIDevice("VMMDev", pInst); H();
3977 if (fMmioReq)
3978 InsertConfigInteger(pCfg, "MmioReq", 1);
3979
3980 Bstr hwVersion;
3981 hrc = pMachine->COMGETTER(HardwareVersion)(hwVersion.asOutParam()); H();
3982 if (hwVersion.compare(Bstr("1").raw()) == 0) /* <= 2.0.x */
3983 InsertConfigInteger(pCfg, "HeapEnabled", 0);
3984 Bstr snapshotFolder;
3985 hrc = pMachine->COMGETTER(SnapshotFolder)(snapshotFolder.asOutParam()); H();
3986 InsertConfigString(pCfg, "GuestCoreDumpDir", snapshotFolder);
3987
3988 /* the VMM device's Main driver */
3989 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3990 InsertConfigString(pLunL0, "Driver", "HGCM");
3991 InsertConfigNode(pLunL0, "Config", &pCfg);
3992
3993 /*
3994 * Attach the status driver.
3995 */
3996 i_attachStatusDriver(pInst, DeviceType_SharedFolder);
3997
3998#ifdef VBOX_WITH_SHARED_CLIPBOARD
3999 /*
4000 * Shared Clipboard.
4001 */
4002 {
4003 ClipboardMode_T enmClipboardMode = ClipboardMode_Disabled;
4004 hrc = pMachine->COMGETTER(ClipboardMode)(&enmClipboardMode); H();
4005# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
4006 BOOL fFileTransfersEnabled;
4007 hrc = pMachine->COMGETTER(ClipboardFileTransfersEnabled)(&fFileTransfersEnabled); H();
4008#endif
4009
4010 /* Load the service */
4011 vrc = pVMMDev->hgcmLoadService("VBoxSharedClipboard", "VBoxSharedClipboard");
4012 if (RT_SUCCESS(vrc))
4013 {
4014 LogRel(("Shared Clipboard: Service loaded\n"));
4015
4016 /* Set initial clipboard mode. */
4017 vrc = i_changeClipboardMode(enmClipboardMode);
4018 AssertLogRelMsg(RT_SUCCESS(vrc), ("Shared Clipboard: Failed to set initial clipboard mode (%d): vrc=%Rrc\n",
4019 enmClipboardMode, vrc));
4020
4021 /* Setup the service. */
4022 VBOXHGCMSVCPARM parm;
4023 HGCMSvcSetU32(&parm, !i_useHostClipboard());
4024 vrc = pVMMDev->hgcmHostCall("VBoxSharedClipboard", VBOX_SHCL_HOST_FN_SET_HEADLESS, 1, &parm);
4025 AssertLogRelMsg(RT_SUCCESS(vrc), ("Shared Clipboard: Failed to set initial headless mode (%RTbool): vrc=%Rrc\n",
4026 !i_useHostClipboard(), vrc));
4027
4028# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
4029 vrc = i_changeClipboardFileTransferMode(RT_BOOL(fFileTransfersEnabled));
4030 AssertLogRelMsg(RT_SUCCESS(vrc), ("Shared Clipboard: Failed to set initial file transfer mode (%u): vrc=%Rrc\n",
4031 fFileTransfersEnabled, vrc));
4032# endif
4033 GuestShCl::createInstance(this /* pConsole */);
4034 vrc = HGCMHostRegisterServiceExtension(&m_hHgcmSvcExtShCl, "VBoxSharedClipboard",
4035 &GuestShCl::hgcmDispatcher,
4036 GuestShClInst());
4037 if (RT_FAILURE(vrc))
4038 Log(("Cannot register VBoxSharedClipboard extension, vrc=%Rrc\n", vrc));
4039 }
4040 else
4041 LogRel(("Shared Clipboard: Not available, vrc=%Rrc\n", vrc));
4042 vrc = VINF_SUCCESS; /* None of the potential failures above are fatal. */
4043 }
4044#endif /* VBOX_WITH_SHARED_CLIPBOARD */
4045
4046 /*
4047 * HGCM HostChannel.
4048 */
4049 {
4050 Bstr value;
4051 hrc = pMachine->GetExtraData(Bstr("HGCM/HostChannel").raw(),
4052 value.asOutParam());
4053
4054 if ( hrc == S_OK
4055 && value == "1")
4056 {
4057 vrc = pVMMDev->hgcmLoadService("VBoxHostChannel", "VBoxHostChannel");
4058 if (RT_FAILURE(vrc))
4059 {
4060 LogRel(("VBoxHostChannel is not available, vrc=%Rrc\n", vrc));
4061 /* That is not a fatal failure. */
4062 vrc = VINF_SUCCESS;
4063 }
4064 }
4065 }
4066
4067#ifdef VBOX_WITH_DRAG_AND_DROP
4068 /*
4069 * Drag and Drop.
4070 */
4071 {
4072 DnDMode_T enmMode = DnDMode_Disabled;
4073 hrc = pMachine->COMGETTER(DnDMode)(&enmMode); H();
4074
4075 /* Load the service */
4076 vrc = pVMMDev->hgcmLoadService("VBoxDragAndDropSvc", "VBoxDragAndDropSvc");
4077 if (RT_FAILURE(vrc))
4078 {
4079 LogRel(("Drag and drop service is not available, vrc=%Rrc\n", vrc));
4080 /* That is not a fatal failure. */
4081 vrc = VINF_SUCCESS;
4082 }
4083 else
4084 {
4085 vrc = HGCMHostRegisterServiceExtension(&m_hHgcmSvcExtDragAndDrop, "VBoxDragAndDropSvc",
4086 &GuestDnD::notifyDnDDispatcher,
4087 GuestDnDInst());
4088 if (RT_FAILURE(vrc))
4089 Log(("Cannot register VBoxDragAndDropSvc extension, vrc=%Rrc\n", vrc));
4090 else
4091 {
4092 LogRel(("Drag and drop service loaded\n"));
4093 vrc = i_changeDnDMode(enmMode);
4094 }
4095 }
4096 }
4097#endif /* VBOX_WITH_DRAG_AND_DROP */
4098
4099 return vrc;
4100}
4101
4102
4103int Console::i_configUsb(ComPtr<IMachine> pMachine, BusAssignmentManager *pBusMgr, PCFGMNODE pRoot, PCFGMNODE pDevices,
4104 KeyboardHIDType_T enmKbdHid, PointingHIDType_T enmPointingHid, PCFGMNODE *ppUsbDevices)
4105{
4106 PCFGMNODE pDev = NULL; /* /Devices/Dev/ */
4107 PCFGMNODE pInst = NULL; /* /Devices/Dev/0/ */
4108 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
4109 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
4110 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */
4111
4112 com::SafeIfaceArray<IUSBController> usbCtrls;
4113 HRESULT hrc = pMachine->COMGETTER(USBControllers)(ComSafeArrayAsOutParam(usbCtrls));
4114 bool fOhciPresent = false; /**< Flag whether at least one OHCI controller is present. */
4115 bool fXhciPresent = false; /**< Flag whether at least one XHCI controller is present. */
4116
4117 if (SUCCEEDED(hrc))
4118 {
4119 for (size_t i = 0; i < usbCtrls.size(); ++i)
4120 {
4121 USBControllerType_T enmCtrlType;
4122 hrc = usbCtrls[i]->COMGETTER(Type)(&enmCtrlType); H();
4123 if (enmCtrlType == USBControllerType_OHCI)
4124 {
4125 fOhciPresent = true;
4126 break;
4127 }
4128 else if (enmCtrlType == USBControllerType_XHCI)
4129 {
4130 fXhciPresent = true;
4131 break;
4132 }
4133 }
4134 }
4135 else if (hrc != E_NOTIMPL)
4136 {
4137 H();
4138 }
4139
4140 /*
4141 * Currently EHCI is only enabled when an OHCI or XHCI controller is present as well.
4142 */
4143 if (fOhciPresent || fXhciPresent)
4144 mfVMHasUsbController = true;
4145
4146 if (mfVMHasUsbController)
4147 {
4148 for (size_t i = 0; i < usbCtrls.size(); ++i)
4149 {
4150 USBControllerType_T enmCtrlType;
4151 hrc = usbCtrls[i]->COMGETTER(Type)(&enmCtrlType); H();
4152
4153 if (enmCtrlType == USBControllerType_OHCI)
4154 {
4155 InsertConfigNode(pDevices, "usb-ohci", &pDev);
4156 InsertConfigNode(pDev, "0", &pInst);
4157 InsertConfigNode(pInst, "Config", &pCfg);
4158 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
4159 hrc = pBusMgr->assignPCIDevice("usb-ohci", pInst); H();
4160 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4161 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
4162 InsertConfigNode(pLunL0, "Config", &pCfg);
4163
4164 /*
4165 * Attach the status driver.
4166 */
4167 i_attachStatusDriver(pInst, DeviceType_USB);
4168 }
4169#ifdef VBOX_WITH_EHCI
4170 else if (enmCtrlType == USBControllerType_EHCI)
4171 {
4172 InsertConfigNode(pDevices, "usb-ehci", &pDev);
4173 InsertConfigNode(pDev, "0", &pInst);
4174 InsertConfigNode(pInst, "Config", &pCfg);
4175 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
4176 hrc = pBusMgr->assignPCIDevice("usb-ehci", pInst); H();
4177
4178 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4179 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
4180 InsertConfigNode(pLunL0, "Config", &pCfg);
4181
4182 /*
4183 * Attach the status driver.
4184 */
4185 i_attachStatusDriver(pInst, DeviceType_USB);
4186 }
4187#endif
4188 else if (enmCtrlType == USBControllerType_XHCI)
4189 {
4190 InsertConfigNode(pDevices, "usb-xhci", &pDev);
4191 InsertConfigNode(pDev, "0", &pInst);
4192 InsertConfigNode(pInst, "Config", &pCfg);
4193 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
4194 hrc = pBusMgr->assignPCIDevice("usb-xhci", pInst); H();
4195
4196 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4197 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
4198 InsertConfigNode(pLunL0, "Config", &pCfg);
4199
4200 InsertConfigNode(pInst, "LUN#1", &pLunL1);
4201 InsertConfigString(pLunL1, "Driver", "VUSBRootHub");
4202 InsertConfigNode(pLunL1, "Config", &pCfg);
4203
4204 /*
4205 * Attach the status driver.
4206 */
4207 i_attachStatusDriver(pInst, DeviceType_USB, 2);
4208 }
4209 } /* for every USB controller. */
4210
4211
4212 /*
4213 * Virtual USB Devices.
4214 */
4215 PCFGMNODE pUsbDevices = NULL;
4216 InsertConfigNode(pRoot, "USB", &pUsbDevices);
4217 *ppUsbDevices = pUsbDevices;
4218
4219#ifdef VBOX_WITH_USB
4220 {
4221 /*
4222 * Global USB options, currently unused as we'll apply the 2.0 -> 1.1 morphing
4223 * on a per device level now.
4224 */
4225 InsertConfigNode(pUsbDevices, "USBProxy", &pCfg);
4226 InsertConfigNode(pCfg, "GlobalConfig", &pCfg);
4227 // This globally enables the 2.0 -> 1.1 device morphing of proxied devices to keep windows quiet.
4228 //InsertConfigInteger(pCfg, "Force11Device", true);
4229 // The following breaks stuff, but it makes MSDs work in vista. (I include it here so
4230 // that it's documented somewhere.) Users needing it can use:
4231 // VBoxManage setextradata "myvm" "VBoxInternal/USB/USBProxy/GlobalConfig/Force11PacketSize" 1
4232 //InsertConfigInteger(pCfg, "Force11PacketSize", true);
4233 }
4234#endif
4235
4236#ifdef VBOX_WITH_USB_CARDREADER
4237 BOOL aEmulatedUSBCardReaderEnabled = FALSE;
4238 hrc = pMachine->COMGETTER(EmulatedUSBCardReaderEnabled)(&aEmulatedUSBCardReaderEnabled); H();
4239 if (aEmulatedUSBCardReaderEnabled)
4240 {
4241 InsertConfigNode(pUsbDevices, "CardReader", &pDev);
4242 InsertConfigNode(pDev, "0", &pInst);
4243 InsertConfigNode(pInst, "Config", &pCfg);
4244
4245 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4246# ifdef VBOX_WITH_USB_CARDREADER_TEST
4247 InsertConfigString(pLunL0, "Driver", "DrvDirectCardReader");
4248 InsertConfigNode(pLunL0, "Config", &pCfg);
4249# else
4250 InsertConfigString(pLunL0, "Driver", "UsbCardReader");
4251 InsertConfigNode(pLunL0, "Config", &pCfg);
4252# endif
4253 }
4254#endif
4255
4256 /* Virtual USB Mouse/Tablet */
4257 if ( enmPointingHid == PointingHIDType_USBMouse
4258 || enmPointingHid == PointingHIDType_USBTablet
4259 || enmPointingHid == PointingHIDType_USBMultiTouch
4260 || enmPointingHid == PointingHIDType_USBMultiTouchScreenPlusPad)
4261 {
4262 InsertConfigNode(pUsbDevices, "HidMouse", &pDev);
4263 InsertConfigNode(pDev, "0", &pInst);
4264 InsertConfigNode(pInst, "Config", &pCfg);
4265
4266 if (enmPointingHid == PointingHIDType_USBMouse)
4267 InsertConfigString(pCfg, "Mode", "relative");
4268 else
4269 InsertConfigString(pCfg, "Mode", "absolute");
4270 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4271 InsertConfigString(pLunL0, "Driver", "MouseQueue");
4272 InsertConfigNode(pLunL0, "Config", &pCfg);
4273 InsertConfigInteger(pCfg, "QueueSize", 128);
4274
4275 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
4276 InsertConfigString(pLunL1, "Driver", "MainMouse");
4277 }
4278 if ( enmPointingHid == PointingHIDType_USBMultiTouch
4279 || enmPointingHid == PointingHIDType_USBMultiTouchScreenPlusPad)
4280 {
4281 InsertConfigNode(pDev, "1", &pInst);
4282 InsertConfigNode(pInst, "Config", &pCfg);
4283
4284 InsertConfigString(pCfg, "Mode", "multitouch");
4285 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4286 InsertConfigString(pLunL0, "Driver", "MouseQueue");
4287 InsertConfigNode(pLunL0, "Config", &pCfg);
4288 InsertConfigInteger(pCfg, "QueueSize", 128);
4289
4290 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
4291 InsertConfigString(pLunL1, "Driver", "MainMouse");
4292 }
4293 if (enmPointingHid == PointingHIDType_USBMultiTouchScreenPlusPad)
4294 {
4295 InsertConfigNode(pDev, "2", &pInst);
4296 InsertConfigNode(pInst, "Config", &pCfg);
4297
4298 InsertConfigString(pCfg, "Mode", "touchpad");
4299 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4300 InsertConfigString(pLunL0, "Driver", "MouseQueue");
4301 InsertConfigNode(pLunL0, "Config", &pCfg);
4302 InsertConfigInteger(pCfg, "QueueSize", 128);
4303
4304 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
4305 InsertConfigString(pLunL1, "Driver", "MainMouse");
4306 }
4307
4308 /* Virtual USB Keyboard */
4309 if (enmKbdHid == KeyboardHIDType_USBKeyboard)
4310 {
4311 InsertConfigNode(pUsbDevices, "HidKeyboard", &pDev);
4312 InsertConfigNode(pDev, "0", &pInst);
4313 InsertConfigNode(pInst, "Config", &pCfg);
4314
4315 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4316 InsertConfigString(pLunL0, "Driver", "KeyboardQueue");
4317 InsertConfigNode(pLunL0, "Config", &pCfg);
4318 InsertConfigInteger(pCfg, "QueueSize", 64);
4319
4320 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
4321 InsertConfigString(pLunL1, "Driver", "MainKeyboard");
4322 }
4323 }
4324
4325 return VINF_SUCCESS;
4326}
4327
4328
4329/**
4330 * Translate IDE StorageControllerType_T to string representation.
4331 */
4332static const char* controllerString(StorageControllerType_T enmType)
4333{
4334 switch (enmType)
4335 {
4336 case StorageControllerType_PIIX3:
4337 return "PIIX3";
4338 case StorageControllerType_PIIX4:
4339 return "PIIX4";
4340 case StorageControllerType_ICH6:
4341 return "ICH6";
4342 default:
4343 return "Unknown";
4344 }
4345}
4346
4347
4348int Console::i_configStorageCtrls(ComPtr<IMachine> pMachine, BusAssignmentManager *pBusMgr, PCVMMR3VTABLE pVMM, PUVM pUVM,
4349 PCFGMNODE pDevices, PCFGMNODE pUsbDevices, PCFGMNODE pBiosCfg, bool *pfFdcEnabled)
4350{
4351 PCFGMNODE pDev = NULL; /* /Devices/Dev/ */
4352 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
4353
4354 com::SafeIfaceArray<IStorageController> ctrls;
4355 PCFGMNODE aCtrlNodes[StorageControllerType_VirtioSCSI + 1] = {};
4356 HRESULT hrc = pMachine->COMGETTER(StorageControllers)(ComSafeArrayAsOutParam(ctrls)); H();
4357
4358 for (size_t i = 0; i < ctrls.size(); ++i)
4359 {
4360 DeviceType_T *paLedDevType = NULL;
4361
4362 StorageControllerType_T enmCtrlType;
4363 hrc = ctrls[i]->COMGETTER(ControllerType)(&enmCtrlType); H();
4364 AssertRelease((unsigned)enmCtrlType < RT_ELEMENTS(aCtrlNodes)
4365 || enmCtrlType == StorageControllerType_USB);
4366
4367 StorageBus_T enmBus;
4368 hrc = ctrls[i]->COMGETTER(Bus)(&enmBus); H();
4369
4370 Bstr controllerName;
4371 hrc = ctrls[i]->COMGETTER(Name)(controllerName.asOutParam()); H();
4372
4373 ULONG ulInstance = 999;
4374 hrc = ctrls[i]->COMGETTER(Instance)(&ulInstance); H();
4375
4376 BOOL fUseHostIOCache;
4377 hrc = ctrls[i]->COMGETTER(UseHostIOCache)(&fUseHostIOCache); H();
4378
4379 BOOL fBootable;
4380 hrc = ctrls[i]->COMGETTER(Bootable)(&fBootable); H();
4381
4382 PCFGMNODE pCtlInst = NULL;
4383 const char *pszCtrlDev = i_storageControllerTypeToStr(enmCtrlType);
4384 if (enmCtrlType != StorageControllerType_USB)
4385 {
4386 /* /Devices/<ctrldev>/ */
4387 pDev = aCtrlNodes[enmCtrlType];
4388 if (!pDev)
4389 {
4390 InsertConfigNode(pDevices, pszCtrlDev, &pDev);
4391 aCtrlNodes[enmCtrlType] = pDev; /* IDE variants are handled in the switch */
4392 }
4393
4394 /* /Devices/<ctrldev>/<instance>/ */
4395 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pCtlInst);
4396
4397 /* Device config: /Devices/<ctrldev>/<instance>/<values> & /ditto/Config/<values> */
4398 InsertConfigInteger(pCtlInst, "Trusted", 1);
4399 InsertConfigNode(pCtlInst, "Config", &pCfg);
4400 }
4401
4402#define MAX_BIOS_LUN_COUNT 4
4403
4404 static const char * const apszBiosConfigScsi[MAX_BIOS_LUN_COUNT] =
4405 { "ScsiLUN1", "ScsiLUN2", "ScsiLUN3", "ScsiLUN4" };
4406
4407 static const char * const apszBiosConfigSata[MAX_BIOS_LUN_COUNT] =
4408 { "SataLUN1", "SataLUN2", "SataLUN3", "SataLUN4" };
4409
4410#undef MAX_BIOS_LUN_COUNT
4411
4412 switch (enmCtrlType)
4413 {
4414 case StorageControllerType_LsiLogic:
4415 {
4416 hrc = pBusMgr->assignPCIDevice("lsilogic", pCtlInst); H();
4417
4418 InsertConfigInteger(pCfg, "Bootable", fBootable);
4419
4420 /* BIOS configuration values, first SCSI controller only. */
4421 if ( !pBusMgr->hasPCIDevice("lsilogic", 1)
4422 && !pBusMgr->hasPCIDevice("buslogic", 0)
4423 && !pBusMgr->hasPCIDevice("lsilogicsas", 0)
4424 && pBiosCfg)
4425 {
4426 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "lsilogicscsi");
4427 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();
4428 }
4429
4430 /* Attach the status driver */
4431 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD),
4432 16, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
4433 break;
4434 }
4435
4436 case StorageControllerType_BusLogic:
4437 {
4438 hrc = pBusMgr->assignPCIDevice("buslogic", pCtlInst); H();
4439
4440 InsertConfigInteger(pCfg, "Bootable", fBootable);
4441
4442 /* BIOS configuration values, first SCSI controller only. */
4443 if ( !pBusMgr->hasPCIDevice("lsilogic", 0)
4444 && !pBusMgr->hasPCIDevice("buslogic", 1)
4445 && !pBusMgr->hasPCIDevice("lsilogicsas", 0)
4446 && pBiosCfg)
4447 {
4448 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "buslogic");
4449 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();
4450 }
4451
4452 /* Attach the status driver */
4453 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD),
4454 16, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
4455 break;
4456 }
4457
4458 case StorageControllerType_IntelAhci:
4459 {
4460 hrc = pBusMgr->assignPCIDevice("ahci", pCtlInst); H();
4461
4462 ULONG cPorts = 0;
4463 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
4464 InsertConfigInteger(pCfg, "PortCount", cPorts);
4465 InsertConfigInteger(pCfg, "Bootable", fBootable);
4466
4467 com::SafeIfaceArray<IMediumAttachment> atts;
4468 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),
4469 ComSafeArrayAsOutParam(atts)); H();
4470
4471 /* Configure the hotpluggable flag for the port. */
4472 for (unsigned idxAtt = 0; idxAtt < atts.size(); ++idxAtt)
4473 {
4474 IMediumAttachment *pMediumAtt = atts[idxAtt];
4475
4476 LONG lPortNum = 0;
4477 hrc = pMediumAtt->COMGETTER(Port)(&lPortNum); H();
4478
4479 BOOL fHotPluggable = FALSE;
4480 hrc = pMediumAtt->COMGETTER(HotPluggable)(&fHotPluggable); H();
4481 if (SUCCEEDED(hrc))
4482 {
4483 PCFGMNODE pPortCfg;
4484 char szName[24];
4485 RTStrPrintf(szName, sizeof(szName), "Port%d", lPortNum);
4486
4487 InsertConfigNode(pCfg, szName, &pPortCfg);
4488 InsertConfigInteger(pPortCfg, "Hotpluggable", fHotPluggable ? 1 : 0);
4489 }
4490 }
4491
4492 /* BIOS configuration values, first AHCI controller only. */
4493 if ( !pBusMgr->hasPCIDevice("ahci", 1)
4494 && pBiosCfg)
4495 {
4496 InsertConfigString(pBiosCfg, "SataHardDiskDevice", "ahci");
4497 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigSata); H();
4498 }
4499
4500 /* Attach the status driver */
4501 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD),
4502 cPorts, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
4503 break;
4504 }
4505
4506 case StorageControllerType_PIIX3:
4507 case StorageControllerType_PIIX4:
4508 case StorageControllerType_ICH6:
4509 {
4510 /*
4511 * IDE (update this when the main interface changes)
4512 */
4513 hrc = pBusMgr->assignPCIDevice("piix3ide", pCtlInst); H();
4514 InsertConfigString(pCfg, "Type", controllerString(enmCtrlType));
4515
4516 /* Attach the status driver */
4517 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD),
4518 4, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
4519
4520 /* IDE flavors */
4521 aCtrlNodes[StorageControllerType_PIIX3] = pDev;
4522 aCtrlNodes[StorageControllerType_PIIX4] = pDev;
4523 aCtrlNodes[StorageControllerType_ICH6] = pDev;
4524 break;
4525 }
4526
4527 case StorageControllerType_I82078:
4528 {
4529 /*
4530 * i82078 Floppy drive controller
4531 */
4532 *pfFdcEnabled = true;
4533 InsertConfigInteger(pCfg, "IRQ", 6);
4534 InsertConfigInteger(pCfg, "DMA", 2);
4535 InsertConfigInteger(pCfg, "MemMapped", 0 );
4536 InsertConfigInteger(pCfg, "IOBase", 0x3f0);
4537
4538 /* Attach the status driver */
4539 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_Floppy),
4540 2, NULL, &mapMediumAttachments, pszCtrlDev, ulInstance);
4541 break;
4542 }
4543
4544 case StorageControllerType_LsiLogicSas:
4545 {
4546 hrc = pBusMgr->assignPCIDevice("lsilogicsas", pCtlInst); H();
4547
4548 InsertConfigString(pCfg, "ControllerType", "SAS1068");
4549 InsertConfigInteger(pCfg, "Bootable", fBootable);
4550
4551 /* BIOS configuration values, first SCSI controller only. */
4552 if ( !pBusMgr->hasPCIDevice("lsilogic", 0)
4553 && !pBusMgr->hasPCIDevice("buslogic", 0)
4554 && !pBusMgr->hasPCIDevice("lsilogicsas", 1)
4555 && pBiosCfg)
4556 {
4557 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "lsilogicsas");
4558 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();
4559 }
4560
4561 ULONG cPorts = 0;
4562 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
4563 InsertConfigInteger(pCfg, "NumPorts", cPorts);
4564
4565 /* Attach the status driver */
4566 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD) /*?*/,
4567 8, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
4568 break;
4569 }
4570
4571 case StorageControllerType_USB:
4572 {
4573 if (pUsbDevices)
4574 {
4575 /*
4576 * USB MSDs are handled a bit different as the device instance
4577 * doesn't match the storage controller instance but the port.
4578 */
4579 InsertConfigNode(pUsbDevices, "Msd", &pDev);
4580 pCtlInst = pDev;
4581 }
4582 else
4583 return pVMM->pfnVMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
4584 N_("There is no USB controller enabled but there\n"
4585 "is at least one USB storage device configured for this VM.\n"
4586 "To fix this problem either enable the USB controller or remove\n"
4587 "the storage device from the VM"));
4588 break;
4589 }
4590
4591 case StorageControllerType_NVMe:
4592 {
4593 hrc = pBusMgr->assignPCIDevice("nvme", pCtlInst); H();
4594
4595 ULONG cPorts = 0;
4596 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
4597 InsertConfigInteger(pCfg, "NamespacesMax", cPorts);
4598
4599 /* Attach the status driver */
4600 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk),
4601 cPorts, NULL, &mapMediumAttachments, pszCtrlDev, ulInstance);
4602 break;
4603 }
4604
4605 case StorageControllerType_VirtioSCSI:
4606 {
4607 hrc = pBusMgr->assignPCIDevice("virtio-scsi", pCtlInst); H();
4608
4609 ULONG cPorts = 0;
4610 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
4611 InsertConfigInteger(pCfg, "NumTargets", cPorts);
4612 InsertConfigInteger(pCfg, "Bootable", fBootable);
4613
4614 /* Attach the status driver */
4615 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD) /*?*/,
4616 cPorts, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
4617 break;
4618 }
4619
4620 default:
4621 AssertLogRelMsgFailedReturn(("invalid storage controller type: %d\n", enmCtrlType), VERR_MAIN_CONFIG_CONSTRUCTOR_IPE);
4622 }
4623
4624 /* Attach the media to the storage controllers. */
4625 com::SafeIfaceArray<IMediumAttachment> atts;
4626 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),
4627 ComSafeArrayAsOutParam(atts)); H();
4628
4629 /* Builtin I/O cache - per device setting. */
4630 BOOL fBuiltinIOCache = true;
4631 hrc = pMachine->COMGETTER(IOCacheEnabled)(&fBuiltinIOCache); H();
4632
4633 bool fInsertDiskIntegrityDrv = false;
4634 Bstr strDiskIntegrityFlag;
4635 hrc = pMachine->GetExtraData(Bstr("VBoxInternal2/EnableDiskIntegrityDriver").raw(),
4636 strDiskIntegrityFlag.asOutParam());
4637 if ( hrc == S_OK
4638 && strDiskIntegrityFlag == "1")
4639 fInsertDiskIntegrityDrv = true;
4640
4641 for (size_t j = 0; j < atts.size(); ++j)
4642 {
4643 IMediumAttachment *pMediumAtt = atts[j];
4644 int vrc = i_configMediumAttachment(pszCtrlDev,
4645 ulInstance,
4646 enmBus,
4647 !!fUseHostIOCache,
4648 enmCtrlType == StorageControllerType_NVMe ? false : !!fBuiltinIOCache,
4649 fInsertDiskIntegrityDrv,
4650 false /* fSetupMerge */,
4651 0 /* uMergeSource */,
4652 0 /* uMergeTarget */,
4653 pMediumAtt,
4654 mMachineState,
4655 NULL /* phrc */,
4656 false /* fAttachDetach */,
4657 false /* fForceUnmount */,
4658 false /* fHotplug */,
4659 pUVM,
4660 pVMM,
4661 paLedDevType,
4662 NULL /* ppLunL0 */);
4663 if (RT_FAILURE(vrc))
4664 return vrc;
4665 }
4666 H();
4667 }
4668 H();
4669
4670 return VINF_SUCCESS;
4671}
4672
4673
4674int Console::i_configNetworkCtrls(ComPtr<IMachine> pMachine, ComPtr<IPlatformProperties> pPlatformProperties,
4675 ChipsetType_T enmChipset, BusAssignmentManager *pBusMgr, PCVMMR3VTABLE pVMM, PUVM pUVM,
4676 PCFGMNODE pDevices, PCFGMNODE pUsbDevices, std::list<BootNic> &llBootNics)
4677{
4678/* Comment out the following line to remove VMWare compatibility hack. */
4679#define VMWARE_NET_IN_SLOT_11
4680
4681 PCFGMNODE pDev = NULL; /* /Devices/Dev/ */
4682 PCFGMNODE pInst = NULL; /* /Devices/Dev/0/ */
4683 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
4684 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
4685
4686 ULONG maxNetworkAdapters;
4687 HRESULT hrc = pPlatformProperties->GetMaxNetworkAdapters(enmChipset, &maxNetworkAdapters); H();
4688
4689#ifdef VMWARE_NET_IN_SLOT_11
4690 bool fSwapSlots3and11 = false;
4691#endif
4692 PCFGMNODE pDevPCNet = NULL; /* PCNet-type devices */
4693 InsertConfigNode(pDevices, "pcnet", &pDevPCNet);
4694#ifdef VBOX_WITH_E1000
4695 PCFGMNODE pDevE1000 = NULL; /* E1000-type devices */
4696 InsertConfigNode(pDevices, "e1000", &pDevE1000);
4697#endif
4698#ifdef VBOX_WITH_VIRTIO
4699 PCFGMNODE pDevVirtioNet = NULL; /* Virtio network devices */
4700 InsertConfigNode(pDevices, "virtio-net", &pDevVirtioNet);
4701#endif /* VBOX_WITH_VIRTIO */
4702 PCFGMNODE pDevDP8390 = NULL; /* DP8390-type devices */
4703 InsertConfigNode(pDevices, "dp8390", &pDevDP8390);
4704 PCFGMNODE pDev3C501 = NULL; /* EtherLink-type devices */
4705 InsertConfigNode(pDevices, "3c501", &pDev3C501);
4706 PCFGMNODE pUsbNet = NULL; /* USB NCM Ethernet devices */
4707
4708 for (ULONG uInstance = 0; uInstance < maxNetworkAdapters; ++uInstance)
4709 {
4710 ComPtr<INetworkAdapter> networkAdapter;
4711 hrc = pMachine->GetNetworkAdapter(uInstance, networkAdapter.asOutParam()); H();
4712 BOOL fEnabledNetAdapter = FALSE;
4713 hrc = networkAdapter->COMGETTER(Enabled)(&fEnabledNetAdapter); H();
4714 if (!fEnabledNetAdapter)
4715 continue;
4716
4717 /*
4718 * The virtual hardware type. Create appropriate device first.
4719 */
4720 const char *pszAdapterName = "pcnet";
4721 NetworkAdapterType_T adapterType;
4722 hrc = networkAdapter->COMGETTER(AdapterType)(&adapterType); H();
4723 switch (adapterType)
4724 {
4725 case NetworkAdapterType_Am79C970A:
4726 case NetworkAdapterType_Am79C973:
4727 case NetworkAdapterType_Am79C960:
4728 pDev = pDevPCNet;
4729 break;
4730#ifdef VBOX_WITH_E1000
4731 case NetworkAdapterType_I82540EM:
4732 case NetworkAdapterType_I82543GC:
4733 case NetworkAdapterType_I82545EM:
4734 pDev = pDevE1000;
4735 pszAdapterName = "e1000";
4736 break;
4737#endif
4738#ifdef VBOX_WITH_VIRTIO
4739 case NetworkAdapterType_Virtio:
4740 pDev = pDevVirtioNet;
4741 pszAdapterName = "virtio-net";
4742 break;
4743#endif /* VBOX_WITH_VIRTIO */
4744 case NetworkAdapterType_NE1000:
4745 case NetworkAdapterType_NE2000:
4746 case NetworkAdapterType_WD8003:
4747 case NetworkAdapterType_WD8013:
4748 case NetworkAdapterType_ELNK2:
4749 pDev = pDevDP8390;
4750 break;
4751 case NetworkAdapterType_ELNK1:
4752 pDev = pDev3C501;
4753 break;
4754 case NetworkAdapterType_UsbNet:
4755 if (!pUsbNet)
4756 InsertConfigNode(pUsbDevices, "UsbNet", &pUsbNet);
4757 pDev = pUsbNet;
4758 pszAdapterName = "UsbNet";
4759 break;
4760 default:
4761 AssertMsgFailed(("Invalid network adapter type '%d' for slot '%d'", adapterType, uInstance));
4762 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
4763 N_("Invalid network adapter type '%d' for slot '%d'"), adapterType, uInstance);
4764 }
4765
4766 InsertConfigNode(pDev, Utf8StrFmt("%u", uInstance).c_str(), &pInst);
4767 /* USB Ethernet is not attached to PCI bus, skip irrelevant bits. */
4768 if (adapterType != NetworkAdapterType_UsbNet)
4769 {
4770 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
4771
4772 int iPCIDeviceNo;
4773 if (enmChipset == ChipsetType_ICH9 || enmChipset == ChipsetType_PIIX3)
4774 {
4775 /* the first network card gets the PCI ID 3, the next 3 gets 8..10,
4776 * next 4 get 16..19. */
4777 switch (uInstance)
4778 {
4779 case 0:
4780 iPCIDeviceNo = 3;
4781 break;
4782 case 1: case 2: case 3:
4783 iPCIDeviceNo = uInstance - 1 + 8;
4784 break;
4785 case 4: case 5: case 6: case 7:
4786 iPCIDeviceNo = uInstance - 4 + 16;
4787 break;
4788 default:
4789 /* auto assignment */
4790 iPCIDeviceNo = -1;
4791 break;
4792 }
4793#ifdef VMWARE_NET_IN_SLOT_11
4794 /*
4795 * Dirty hack for PCI slot compatibility with VMWare,
4796 * it assigns slot 0x11 to the first network controller.
4797 */
4798 if (iPCIDeviceNo == 3 && adapterType == NetworkAdapterType_I82545EM)
4799 {
4800 iPCIDeviceNo = 0x11;
4801 fSwapSlots3and11 = true;
4802 }
4803 else if (iPCIDeviceNo == 0x11 && fSwapSlots3and11)
4804 iPCIDeviceNo = 3;
4805#endif
4806 }
4807 else /* Platforms other than x86 just use the auto assignment, no slot swap hack there. */
4808 iPCIDeviceNo = -1;
4809
4810 PCIBusAddress PCIAddr = PCIBusAddress(0, iPCIDeviceNo, 0);
4811 hrc = pBusMgr->assignPCIDevice(pszAdapterName, pInst, PCIAddr); H();
4812
4813 InsertConfigNode(pInst, "Config", &pCfg);
4814#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE /* not safe here yet. */ /** @todo Make PCNet ring-0 safe on 32-bit mac kernels! */
4815 if (pDev == pDevPCNet)
4816 InsertConfigInteger(pCfg, "R0Enabled", false);
4817#endif
4818 /*
4819 * Collect information needed for network booting and add it to the list.
4820 */
4821 BootNic nic;
4822
4823 nic.mInstance = uInstance;
4824 /* Could be updated by reference, if auto assigned */
4825 nic.mPCIAddress = PCIAddr;
4826
4827 hrc = networkAdapter->COMGETTER(BootPriority)(&nic.mBootPrio); H();
4828
4829 llBootNics.push_back(nic);
4830
4831 /*
4832 * The virtual hardware type. PCNet supports three types, E1000 three,
4833 * but VirtIO only one.
4834 */
4835 switch (adapterType)
4836 {
4837 case NetworkAdapterType_Am79C970A:
4838 InsertConfigString(pCfg, "ChipType", "Am79C970A");
4839 break;
4840 case NetworkAdapterType_Am79C973:
4841 InsertConfigString(pCfg, "ChipType", "Am79C973");
4842 break;
4843 case NetworkAdapterType_Am79C960:
4844 InsertConfigString(pCfg, "ChipType", "Am79C960");
4845 break;
4846 case NetworkAdapterType_I82540EM:
4847 InsertConfigInteger(pCfg, "AdapterType", 0);
4848 break;
4849 case NetworkAdapterType_I82543GC:
4850 InsertConfigInteger(pCfg, "AdapterType", 1);
4851 break;
4852 case NetworkAdapterType_I82545EM:
4853 InsertConfigInteger(pCfg, "AdapterType", 2);
4854 break;
4855 case NetworkAdapterType_Virtio:
4856 break;
4857 case NetworkAdapterType_NE1000:
4858 InsertConfigString(pCfg, "DeviceType", "NE1000");
4859 break;
4860 case NetworkAdapterType_NE2000:
4861 InsertConfigString(pCfg, "DeviceType", "NE2000");
4862 break;
4863 case NetworkAdapterType_WD8003:
4864 InsertConfigString(pCfg, "DeviceType", "WD8003");
4865 break;
4866 case NetworkAdapterType_WD8013:
4867 InsertConfigString(pCfg, "DeviceType", "WD8013");
4868 break;
4869 case NetworkAdapterType_ELNK2:
4870 InsertConfigString(pCfg, "DeviceType", "3C503");
4871 break;
4872 case NetworkAdapterType_ELNK1:
4873 break;
4874 case NetworkAdapterType_UsbNet: /* fall through */
4875 case NetworkAdapterType_Null: AssertFailedBreak(); /* (compiler warnings) */
4876#ifdef VBOX_WITH_XPCOM_CPP_ENUM_HACK
4877 case NetworkAdapterType_32BitHack: AssertFailedBreak(); /* (compiler warnings) */
4878#endif
4879 }
4880 }
4881 else
4882 InsertConfigNode(pInst, "Config", &pCfg);
4883
4884 /*
4885 * Get the MAC address and convert it to binary representation
4886 */
4887 Bstr macAddr;
4888 hrc = networkAdapter->COMGETTER(MACAddress)(macAddr.asOutParam()); H();
4889 Assert(!macAddr.isEmpty());
4890 Utf8Str macAddrUtf8 = macAddr;
4891#ifdef VBOX_WITH_CLOUD_NET
4892 NetworkAttachmentType_T eAttachmentType;
4893 hrc = networkAdapter->COMGETTER(AttachmentType)(&eAttachmentType); H();
4894 if (eAttachmentType == NetworkAttachmentType_Cloud)
4895 {
4896 mGateway.setLocalMacAddress(macAddrUtf8);
4897 /* We'll insert cloud MAC later, when it becomes known. */
4898 }
4899 else
4900 {
4901#endif
4902 char *macStr = (char*)macAddrUtf8.c_str();
4903 Assert(strlen(macStr) == 12);
4904 RTMAC Mac;
4905 RT_ZERO(Mac);
4906 char *pMac = (char*)&Mac;
4907 for (uint32_t i = 0; i < 6; ++i)
4908 {
4909 int c1 = *macStr++ - '0';
4910 if (c1 > 9)
4911 c1 -= 7;
4912 int c2 = *macStr++ - '0';
4913 if (c2 > 9)
4914 c2 -= 7;
4915 *pMac++ = (char)(((c1 & 0x0f) << 4) | (c2 & 0x0f));
4916 }
4917 InsertConfigBytes(pCfg, "MAC", &Mac, sizeof(Mac));
4918#ifdef VBOX_WITH_CLOUD_NET
4919 }
4920#endif
4921 /*
4922 * Check if the cable is supposed to be unplugged
4923 */
4924 BOOL fCableConnected;
4925 hrc = networkAdapter->COMGETTER(CableConnected)(&fCableConnected); H();
4926 InsertConfigInteger(pCfg, "CableConnected", fCableConnected ? 1 : 0);
4927
4928 /* No line speed for USB Ethernet. */
4929 if (adapterType != NetworkAdapterType_UsbNet)
4930 {
4931 /*
4932 * Line speed to report from custom drivers
4933 */
4934 ULONG ulLineSpeed;
4935 hrc = networkAdapter->COMGETTER(LineSpeed)(&ulLineSpeed); H();
4936 InsertConfigInteger(pCfg, "LineSpeed", ulLineSpeed);
4937 }
4938
4939 /*
4940 * Attach the status driver.
4941 */
4942 i_attachStatusDriver(pInst, DeviceType_Network);
4943
4944 /*
4945 * Configure the network card now
4946 */
4947 bool fIgnoreConnectFailure = mMachineState == MachineState_Restoring;
4948 int vrc = i_configNetwork(pszAdapterName,
4949 uInstance,
4950 0,
4951 networkAdapter,
4952 pCfg,
4953 pLunL0,
4954 pInst,
4955 false /*fAttachDetach*/,
4956 fIgnoreConnectFailure,
4957 pUVM,
4958 pVMM);
4959 if (RT_FAILURE(vrc))
4960 return vrc;
4961 }
4962
4963 return VINF_SUCCESS;
4964}
4965
4966
4967int Console::i_configGuestDbg(ComPtr<IVirtualBox> pVBox, ComPtr<IMachine> pMachine, PCFGMNODE pRoot)
4968{
4969 PCFGMNODE pDbgf;
4970 InsertConfigNode(pRoot, "DBGF", &pDbgf);
4971
4972 /* Paths to search for debug info and such things. */
4973 Bstr bstr;
4974 HRESULT hrc = pMachine->COMGETTER(SettingsFilePath)(bstr.asOutParam()); H();
4975 Utf8Str strSettingsPath(bstr);
4976 bstr.setNull();
4977 strSettingsPath.stripFilename();
4978 strSettingsPath.append("/");
4979
4980 char szHomeDir[RTPATH_MAX + 1];
4981 int vrc2 = RTPathUserHome(szHomeDir, sizeof(szHomeDir) - 1);
4982 if (RT_FAILURE(vrc2))
4983 szHomeDir[0] = '\0';
4984 RTPathEnsureTrailingSeparator(szHomeDir, sizeof(szHomeDir));
4985
4986
4987 Utf8Str strPath;
4988 strPath.append(strSettingsPath).append("debug/;");
4989 strPath.append(strSettingsPath).append(";");
4990 strPath.append("cache*").append(strSettingsPath).append("dbgcache/;"); /* handy for symlinking to actual cache */
4991 strPath.append(szHomeDir);
4992
4993 InsertConfigString(pDbgf, "Path", strPath.c_str());
4994
4995 /* Tracing configuration. */
4996 BOOL fTracingEnabled;
4997 hrc = pMachine->COMGETTER(TracingEnabled)(&fTracingEnabled); H();
4998 if (fTracingEnabled)
4999 InsertConfigInteger(pDbgf, "TracingEnabled", 1);
5000
5001 hrc = pMachine->COMGETTER(TracingConfig)(bstr.asOutParam()); H();
5002 if (fTracingEnabled)
5003 InsertConfigString(pDbgf, "TracingConfig", bstr);
5004
5005 /* Debugger console config. */
5006 PCFGMNODE pDbgc;
5007 InsertConfigNode(pRoot, "DBGC", &pDbgc);
5008
5009 hrc = pVBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
5010 Utf8Str strVBoxHome = bstr;
5011 bstr.setNull();
5012 if (strVBoxHome.isNotEmpty())
5013 strVBoxHome.append("/");
5014 else
5015 {
5016 strVBoxHome = szHomeDir;
5017 strVBoxHome.append("/.vbox");
5018 }
5019
5020 Utf8Str strFile(strVBoxHome);
5021 strFile.append("dbgc-history");
5022 InsertConfigString(pDbgc, "HistoryFile", strFile);
5023
5024 strFile = strSettingsPath;
5025 strFile.append("dbgc-init");
5026 InsertConfigString(pDbgc, "LocalInitScript", strFile);
5027
5028 strFile = strVBoxHome;
5029 strFile.append("dbgc-init");
5030 InsertConfigString(pDbgc, "GlobalInitScript", strFile);
5031
5032 /*
5033 * Configure guest debug settings.
5034 */
5035 ComObjPtr<IGuestDebugControl> ptrGstDbgCtrl;
5036 GuestDebugProvider_T enmGstDbgProvider = GuestDebugProvider_None;
5037
5038 hrc = pMachine->COMGETTER(GuestDebugControl)(ptrGstDbgCtrl.asOutParam()); H();
5039 hrc = ptrGstDbgCtrl->COMGETTER(DebugProvider)(&enmGstDbgProvider); H();
5040 if (enmGstDbgProvider != GuestDebugProvider_None)
5041 {
5042 GuestDebugIoProvider_T enmGstDbgIoProvider = GuestDebugIoProvider_None;
5043 hrc = ptrGstDbgCtrl->COMGETTER(DebugIoProvider)(&enmGstDbgIoProvider); H();
5044 hrc = ptrGstDbgCtrl->COMGETTER(DebugAddress)(bstr.asOutParam()); H();
5045 Utf8Str strAddress = bstr;
5046 bstr.setNull();
5047
5048 ULONG ulPort = 0;
5049 hrc = ptrGstDbgCtrl->COMGETTER(DebugPort)(&ulPort); H();
5050
5051 PCFGMNODE pDbgSettings;
5052 InsertConfigNode(pDbgc, "Dbg", &pDbgSettings);
5053 InsertConfigString(pDbgSettings, "Address", strAddress);
5054 InsertConfigInteger(pDbgSettings, "Port", ulPort);
5055
5056 switch (enmGstDbgProvider)
5057 {
5058 case GuestDebugProvider_Native:
5059 InsertConfigString(pDbgSettings, "StubType", "Native");
5060 break;
5061 case GuestDebugProvider_GDB:
5062 InsertConfigString(pDbgSettings, "StubType", "Gdb");
5063 break;
5064 case GuestDebugProvider_KD:
5065 InsertConfigString(pDbgSettings, "StubType", "Kd");
5066 break;
5067 default:
5068 AssertFailed();
5069 break;
5070 }
5071
5072 switch (enmGstDbgIoProvider)
5073 {
5074 case GuestDebugIoProvider_TCP:
5075 InsertConfigString(pDbgSettings, "Provider", "tcp");
5076 break;
5077 case GuestDebugIoProvider_UDP:
5078 InsertConfigString(pDbgSettings, "Provider", "udp");
5079 break;
5080 case GuestDebugIoProvider_IPC:
5081 InsertConfigString(pDbgSettings, "Provider", "ipc");
5082 break;
5083 default:
5084 AssertFailed();
5085 break;
5086 }
5087 }
5088
5089 return VINF_SUCCESS;
5090}
5091
5092
5093int Console::i_configGraphicsController(PCFGMNODE pDevices,
5094 const GraphicsControllerType_T enmGraphicsController,
5095 BusAssignmentManager *pBusMgr,
5096 const ComPtr<IMachine> &ptrMachine,
5097 const ComPtr<IGraphicsAdapter> &ptrGraphicsAdapter,
5098 const ComPtr<IFirmwareSettings> &ptrFirmwareSettings,
5099 bool fForceVmSvga3, bool fExposeLegacyVga)
5100{
5101 // InsertConfig* throws
5102 try
5103 {
5104 PCFGMNODE pDev, pInst, pCfg, pLunL0;
5105 HRESULT hrc;
5106 Bstr bstr;
5107 const char *pcszDevice = "vga";
5108
5109 InsertConfigNode(pDevices, pcszDevice, &pDev);
5110 InsertConfigNode(pDev, "0", &pInst);
5111 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
5112
5113 hrc = pBusMgr->assignPCIDevice(pcszDevice, pInst); H();
5114 InsertConfigNode(pInst, "Config", &pCfg);
5115 ULONG cVRamMBs;
5116 hrc = ptrGraphicsAdapter->COMGETTER(VRAMSize)(&cVRamMBs); H();
5117 InsertConfigInteger(pCfg, "VRamSize", cVRamMBs * _1M);
5118 ULONG cMonitorCount;
5119 hrc = ptrGraphicsAdapter->COMGETTER(MonitorCount)(&cMonitorCount); H();
5120 InsertConfigInteger(pCfg, "MonitorCount", cMonitorCount);
5121
5122 BOOL f3DEnabled = FALSE;
5123 hrc = ptrGraphicsAdapter->IsFeatureEnabled(GraphicsFeature_Acceleration3D, &f3DEnabled); H();
5124 InsertConfigInteger(pCfg, "3DEnabled", f3DEnabled);
5125
5126 i_attachStatusDriver(pInst, DeviceType_Graphics3D);
5127
5128#ifdef VBOX_WITH_VMSVGA
5129 if ( enmGraphicsController == GraphicsControllerType_VMSVGA
5130 || enmGraphicsController == GraphicsControllerType_VBoxSVGA)
5131 {
5132 InsertConfigInteger(pCfg, "VMSVGAEnabled", true);
5133 if (enmGraphicsController == GraphicsControllerType_VMSVGA)
5134 {
5135 InsertConfigInteger(pCfg, "VMSVGAPciBarLayout", true);
5136 InsertConfigInteger(pCfg, "VMSVGAPciId", true);
5137 }
5138# ifdef VBOX_WITH_VMSVGA3D
5139 InsertConfigInteger(pCfg, "VMSVGA3dEnabled", f3DEnabled);
5140# else
5141 LogRel(("VMSVGA3d not available in this build!\n"));
5142# endif
5143
5144 InsertConfigInteger(pCfg, "VmSvga3", fForceVmSvga3);
5145 InsertConfigInteger(pCfg, "VmSvgaExposeLegacyVga", fExposeLegacyVga);
5146 }
5147#else
5148 RT_NOREF(enmGraphicsController, fForceVmSvga3, fExposeLegacyVga);
5149#endif /* !VBOX_WITH_VMSVGA */
5150
5151 /* Custom VESA mode list */
5152 unsigned cModes = 0;
5153 for (unsigned iMode = 1; iMode <= 16; ++iMode)
5154 {
5155 char szExtraDataKey[sizeof("CustomVideoModeXX")];
5156 RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%u", iMode);
5157 hrc = ptrMachine->GetExtraData(Bstr(szExtraDataKey).raw(), bstr.asOutParam()); H();
5158 if (bstr.isEmpty())
5159 break;
5160 InsertConfigString(pCfg, szExtraDataKey, bstr);
5161 ++cModes;
5162 }
5163 InsertConfigInteger(pCfg, "CustomVideoModes", cModes);
5164
5165 /* VESA height reduction */
5166 ULONG ulHeightReduction;
5167 IFramebuffer *pFramebuffer = NULL;
5168 hrc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
5169 if (SUCCEEDED(hrc) && pFramebuffer)
5170 {
5171 hrc = pFramebuffer->COMGETTER(HeightReduction)(&ulHeightReduction); H();
5172 pFramebuffer->Release();
5173 pFramebuffer = NULL;
5174 }
5175 else
5176 {
5177 /* If framebuffer is not available, there is no height reduction. */
5178 ulHeightReduction = 0;
5179 }
5180 InsertConfigInteger(pCfg, "HeightReduction", ulHeightReduction);
5181
5182 /*
5183 * BIOS logo
5184 */
5185 BOOL fFadeIn;
5186 hrc = ptrFirmwareSettings->COMGETTER(LogoFadeIn)(&fFadeIn); H();
5187 InsertConfigInteger(pCfg, "FadeIn", fFadeIn ? 1 : 0);
5188 BOOL fFadeOut;
5189 hrc = ptrFirmwareSettings->COMGETTER(LogoFadeOut)(&fFadeOut); H();
5190 InsertConfigInteger(pCfg, "FadeOut", fFadeOut ? 1: 0);
5191 ULONG logoDisplayTime;
5192 hrc = ptrFirmwareSettings->COMGETTER(LogoDisplayTime)(&logoDisplayTime); H();
5193 InsertConfigInteger(pCfg, "LogoTime", logoDisplayTime);
5194 Bstr bstrLogoImagePath;
5195 hrc = ptrFirmwareSettings->COMGETTER(LogoImagePath)(bstrLogoImagePath.asOutParam()); H();
5196 InsertConfigString(pCfg, "LogoFile", bstrLogoImagePath);
5197
5198 /*
5199 * Boot menu
5200 */
5201 FirmwareBootMenuMode_T enmBootMenuMode;
5202 int iShowBootMenu;
5203 hrc = ptrFirmwareSettings->COMGETTER(BootMenuMode)(&enmBootMenuMode); H();
5204 switch (enmBootMenuMode)
5205 {
5206 case FirmwareBootMenuMode_Disabled: iShowBootMenu = 0; break;
5207 case FirmwareBootMenuMode_MenuOnly: iShowBootMenu = 1; break;
5208 default: iShowBootMenu = 2; break;
5209 }
5210 InsertConfigInteger(pCfg, "ShowBootMenu", iShowBootMenu);
5211
5212 /* Attach the display. */
5213 InsertConfigNode(pInst, "LUN#0", &pLunL0);
5214 InsertConfigString(pLunL0, "Driver", "MainDisplay");
5215 InsertConfigNode(pLunL0, "Config", &pCfg);
5216 }
5217 catch (ConfigError &x)
5218 {
5219 // InsertConfig threw something:
5220 return x.m_vrc;
5221 }
5222
5223 return VINF_SUCCESS;
5224}
5225
5226
5227#if defined(VBOX_WITH_TPM)
5228int Console::i_configTpm(ComPtr<ITrustedPlatformModule> pTpm, TpmType_T enmTpmType, PCFGMNODE pDevices,
5229 RTGCPHYS GCPhysTpmMmio, uint32_t uIrq, RTGCPHYS GCPhysTpmPpi, bool fCrb)
5230{
5231 Assert(enmTpmType != TpmType_None);
5232
5233 // InsertConfig* throws
5234 try
5235 {
5236 HRESULT hrc;
5237 Bstr bstr;
5238 PCFGMNODE pDev = NULL; /* /Devices/Dev/ */
5239 PCFGMNODE pInst = NULL; /* /Devices/Dev/0/ */
5240 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
5241 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
5242 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver */
5243
5244 InsertConfigNode(pDevices, "tpm", &pDev);
5245 InsertConfigNode(pDev, "0", &pInst);
5246 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
5247 InsertConfigNode(pInst, "Config", &pCfg);
5248 InsertConfigInteger(pCfg, "MmioBase", GCPhysTpmMmio);
5249 InsertConfigInteger(pCfg, "Irq", uIrq);
5250 InsertConfigInteger(pCfg, "Crb", fCrb ? 1 : 0); /* boolean */
5251
5252 InsertConfigNode(pInst, "LUN#0", &pLunL0);
5253
5254 switch (enmTpmType)
5255 {
5256 case TpmType_v1_2:
5257 case TpmType_v2_0:
5258 InsertConfigString(pLunL0, "Driver", "TpmEmuTpms");
5259 InsertConfigNode(pLunL0, "Config", &pCfg);
5260 InsertConfigInteger(pCfg, "TpmVersion", enmTpmType == TpmType_v1_2 ? 1 : 2);
5261 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
5262 InsertConfigString(pLunL1, "Driver", "NvramStore");
5263 break;
5264 case TpmType_Host:
5265#if defined(RT_OS_LINUX) || defined(RT_OS_WINDOWS)
5266 InsertConfigString(pLunL0, "Driver", "TpmHost");
5267 InsertConfigNode(pLunL0, "Config", &pCfg);
5268#endif
5269 break;
5270 case TpmType_Swtpm:
5271 hrc = pTpm->COMGETTER(Location)(bstr.asOutParam()); H();
5272 InsertConfigString(pLunL0, "Driver", "TpmEmu");
5273 InsertConfigNode(pLunL0, "Config", &pCfg);
5274 InsertConfigString(pCfg, "Location", bstr);
5275 break;
5276 default:
5277 AssertFailedBreak();
5278 }
5279
5280 if (GCPhysTpmPpi != RTGCPHYS_MAX)
5281 {
5282 /* Add the device for the physical presence interface. */
5283 InsertConfigNode( pDevices, "tpm-ppi", &pDev);
5284 InsertConfigNode( pDev, "0", &pInst);
5285 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
5286 InsertConfigNode( pInst, "Config", &pCfg);
5287 InsertConfigInteger(pCfg, "MmioBase", GCPhysTpmPpi);
5288 }
5289 }
5290 catch (ConfigError &x)
5291 {
5292 // InsertConfig threw something:
5293 return x.m_vrc;
5294 }
5295
5296 return VINF_SUCCESS;
5297}
5298#endif /* VBOX_WITH_TPM */
5299
5300#undef H
5301#undef VRC
5302
5303#ifndef VBOX_WITH_EFI_IN_DD2
5304DECLHIDDEN(int) findEfiRom(IVirtualBox* vbox, PlatformArchitecture_T aPlatformArchitecture, FirmwareType_T aFirmwareType, Utf8Str *pEfiRomFile)
5305{
5306 Bstr aFilePath, empty;
5307 BOOL fPresent = FALSE;
5308 HRESULT hrc = vbox->CheckFirmwarePresent(aPlatformArchitecture, aFirmwareType, empty.raw(),
5309 empty.asOutParam(), aFilePath.asOutParam(), &fPresent);
5310 AssertComRCReturn(hrc, Global::vboxStatusCodeFromCOM(hrc));
5311
5312 if (!fPresent)
5313 {
5314 LogRel(("Failed to find an EFI ROM file.\n"));
5315 return VERR_FILE_NOT_FOUND;
5316 }
5317
5318 *pEfiRomFile = Utf8Str(aFilePath);
5319
5320 return VINF_SUCCESS;
5321}
5322#endif
Note: See TracBrowser for help on using the repository browser.

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