VirtualBox

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

Last change on this file since 88700 was 88672, checked in by vboxsync, 4 years ago

Audio: Use HostAudioWas on windows 10 instead of DSound. Only set the StreamName CFGM value for host audio drivers who needs it (PulseAudio and now WAS). Renamed StreamName to VmName. Added VmUuid to WAS. bugref:9890

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

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