VirtualBox

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

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

Audio/VaKit: Made the Validation Kit driver actually being used + compiled if VBOX_WITH_AUDIO_VALIDATIONKIT is set. Also added some runtime extra-setting to enable/disable it. bugref:9890

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 263.5 KB
Line 
1/* $Id: ConsoleImpl2.cpp 88879 2021-05-05 15:42:48Z 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 * Audio configuration.
2974 */
2975
2976 /*
2977 * AC'97 ICH / SoundBlaster16 audio / Intel HD Audio.
2978 */
2979 BOOL fAudioEnabled = FALSE;
2980 ComPtr<IAudioAdapter> audioAdapter;
2981 hrc = pMachine->COMGETTER(AudioAdapter)(audioAdapter.asOutParam()); H();
2982 if (audioAdapter)
2983 {
2984 hrc = audioAdapter->COMGETTER(Enabled)(&fAudioEnabled); H();
2985 }
2986
2987 if (fAudioEnabled)
2988 {
2989 AudioControllerType_T enmAudioController;
2990 hrc = audioAdapter->COMGETTER(AudioController)(&enmAudioController); H();
2991 AudioCodecType_T enmAudioCodec;
2992 hrc = audioAdapter->COMGETTER(AudioCodec)(&enmAudioCodec); H();
2993
2994 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/Device/TimerHz", &strTmp);
2995 const uint64_t uTimerHz = strTmp.toUInt64();
2996
2997 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/Device/BufSizeInMs", &strTmp);
2998 const uint64_t uBufSizeInMs = strTmp.toUInt64();
2999
3000 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/Device/BufSizeOutMs", &strTmp);
3001 const uint64_t uBufSizeOutMs = strTmp.toUInt64();
3002
3003 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/Debug/Enabled", &strTmp);
3004 const bool fDebugEnabled = strTmp.equalsIgnoreCase("true") || strTmp.equalsIgnoreCase("1");
3005
3006 Utf8Str strDebugPathOut;
3007 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/Debug/PathOut", &strDebugPathOut);
3008
3009#ifdef VBOX_WITH_AUDIO_VALIDATIONKIT
3010 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/VaKit/Enabled", &strTmp);
3011 const bool fVaKitEnabled = strTmp.equalsIgnoreCase("true") || strTmp.equalsIgnoreCase("1");
3012#endif
3013 /** @todo Implement an audio device class, similar to the audio backend class, to construct the common stuff
3014 * without duplicating (more) code. */
3015
3016 const char *pszAudioDevice;
3017 switch (enmAudioController)
3018 {
3019 case AudioControllerType_AC97:
3020 {
3021 /* ICH AC'97. */
3022 pszAudioDevice = "ichac97";
3023
3024 InsertConfigNode(pDevices, pszAudioDevice, &pDev);
3025 InsertConfigNode(pDev, "0", &pInst);
3026 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3027 hrc = pBusMgr->assignPCIDevice(pszAudioDevice, pInst); H();
3028 InsertConfigNode(pInst, "Config", &pCfg);
3029 switch (enmAudioCodec)
3030 {
3031 case AudioCodecType_STAC9700:
3032 InsertConfigString(pCfg, "Codec", "STAC9700");
3033 break;
3034 case AudioCodecType_AD1980:
3035 InsertConfigString(pCfg, "Codec", "AD1980");
3036 break;
3037 default: AssertFailedBreak();
3038 }
3039 if (uTimerHz)
3040 InsertConfigInteger(pCfg, "TimerHz", uTimerHz);
3041 if (uBufSizeInMs)
3042 InsertConfigInteger(pCfg, "BufSizeInMs", uBufSizeInMs);
3043 if (uBufSizeOutMs)
3044 InsertConfigInteger(pCfg, "BufSizeOutMs", uBufSizeOutMs);
3045 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
3046 if (strDebugPathOut.isNotEmpty())
3047 InsertConfigString(pCfg, "DebugPathOut", strDebugPathOut);
3048 break;
3049 }
3050 case AudioControllerType_SB16:
3051 {
3052 /* Legacy SoundBlaster16. */
3053 pszAudioDevice = "sb16";
3054
3055 InsertConfigNode(pDevices, pszAudioDevice, &pDev);
3056 InsertConfigNode(pDev, "0", &pInst);
3057 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3058 InsertConfigNode(pInst, "Config", &pCfg);
3059 InsertConfigInteger(pCfg, "IRQ", 5);
3060 InsertConfigInteger(pCfg, "DMA", 1);
3061 InsertConfigInteger(pCfg, "DMA16", 5);
3062 InsertConfigInteger(pCfg, "Port", 0x220);
3063 InsertConfigInteger(pCfg, "Version", 0x0405);
3064 if (uTimerHz)
3065 InsertConfigInteger(pCfg, "TimerHz", uTimerHz);
3066 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
3067 if (strDebugPathOut.isNotEmpty())
3068 InsertConfigString(pCfg, "DebugPathOut", strDebugPathOut);
3069 break;
3070 }
3071 case AudioControllerType_HDA:
3072 {
3073 /* Intel HD Audio. */
3074 pszAudioDevice = "hda";
3075
3076 InsertConfigNode(pDevices, pszAudioDevice, &pDev);
3077 InsertConfigNode(pDev, "0", &pInst);
3078 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3079 hrc = pBusMgr->assignPCIDevice(pszAudioDevice, pInst); H();
3080 InsertConfigNode(pInst, "Config", &pCfg);
3081 if (uTimerHz)
3082 InsertConfigInteger(pCfg, "TimerHz", uTimerHz);
3083 if (uBufSizeInMs)
3084 InsertConfigInteger(pCfg, "BufSizeInMs", uBufSizeInMs);
3085 if (uBufSizeOutMs)
3086 InsertConfigInteger(pCfg, "BufSizeOutMs", uBufSizeOutMs);
3087 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
3088 if (strDebugPathOut.isNotEmpty())
3089 InsertConfigString(pCfg, "DebugPathOut", strDebugPathOut);
3090
3091 /*
3092 * HDA-specific parameters.
3093 */
3094 uint64_t uTmp;
3095 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/Device/PosAdjustEnabled", &strTmp);
3096 if (strTmp.isNotEmpty())
3097 InsertConfigInteger(pCfg, "PosAdjustEnabled", strTmp.equalsIgnoreCase("true")
3098 || strTmp.equalsIgnoreCase("1"));
3099
3100 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/Device/PosAdjustFrames", &strTmp);
3101 if (strTmp.isNotEmpty())
3102 {
3103 uTmp = strTmp.toUInt64(); /* Ditto. */
3104 InsertConfigInteger(pCfg, "PosAdjustFrames", uTmp);
3105 }
3106
3107 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/Device/TransferHeuristicsEnabled", &strTmp);
3108 if (strTmp.isNotEmpty())
3109 InsertConfigInteger(pCfg, "TransferHeuristicsEnabled", strTmp.equalsIgnoreCase("true")
3110 || strTmp.equalsIgnoreCase("1"));
3111 break;
3112 }
3113 default:
3114 pszAudioDevice = "oops";
3115 AssertFailedBreak();
3116 }
3117
3118 PCFGMNODE pCfgAudioAdapter = NULL;
3119 InsertConfigNode(pInst, "AudioConfig", &pCfgAudioAdapter);
3120 SafeArray<BSTR> audioProps;
3121 hrc = audioAdapter->COMGETTER(PropertiesList)(ComSafeArrayAsOutParam(audioProps)); H();
3122
3123 std::list<Utf8Str> audioPropertyNamesList;
3124 for (size_t i = 0; i < audioProps.size(); ++i)
3125 {
3126 Bstr bstrValue;
3127 audioPropertyNamesList.push_back(Utf8Str(audioProps[i]));
3128 hrc = audioAdapter->GetProperty(audioProps[i], bstrValue.asOutParam());
3129 Utf8Str strKey(audioProps[i]);
3130 InsertConfigString(pCfgAudioAdapter, strKey.c_str(), bstrValue);
3131 }
3132
3133 /*
3134 * The audio driver.
3135 */
3136 AudioDriverType_T enmAudioDriver;
3137 hrc = audioAdapter->COMGETTER(AudioDriver)(&enmAudioDriver); H();
3138 const char *pszAudioDriver;
3139 switch (enmAudioDriver)
3140 {
3141 case AudioDriverType_Null:
3142 pszAudioDriver = "NullAudio";
3143 break;
3144#ifdef RT_OS_WINDOWS
3145# ifdef VBOX_WITH_WINMM
3146 case AudioDriverType_WinMM:
3147# error "Port WinMM audio backend!" /** @todo Still needed? */
3148 break;
3149# endif
3150 case AudioDriverType_DirectSound:
3151 /* Use the windows audio session (WAS) API rather than Direct Sound on windows
3152 versions we've tested it on (currently W10+). Since Vista, Direct Sound has
3153 been emulated on top of WAS according to the docs, so better use WAS directly. */
3154 pszAudioDriver = "DSoundAudio";
3155 if (RTSystemGetNtVersion() >= RTSYSTEM_MAKE_NT_VERSION(10,0,0))
3156 pszAudioDriver = "HostAudioWas";
3157 break;
3158#endif /* RT_OS_WINDOWS */
3159#ifdef RT_OS_SOLARIS
3160 case AudioDriverType_SolAudio:
3161 /* Should not happen, as the Solaris Audio backend is not around anymore.
3162 * Remove this sometime later. */
3163 LogRel(("Audio: WARNING: Solaris Audio is deprecated, please switch to OSS!\n"));
3164 LogRel(("Audio: Automatically setting host audio backend to OSS\n"));
3165
3166 /* Manually set backend to OSS for now. */
3167 pszAudioDriver = "OSSAudio";
3168 break;
3169#endif
3170#ifdef VBOX_WITH_AUDIO_OSS
3171 case AudioDriverType_OSS:
3172 pszAudioDriver = "OSSAudio";
3173 break;
3174#endif
3175#ifdef VBOX_WITH_AUDIO_ALSA
3176 case AudioDriverType_ALSA:
3177 pszAudioDriver = "ALSAAudio";
3178 break;
3179#endif
3180#ifdef VBOX_WITH_AUDIO_PULSE
3181 case AudioDriverType_Pulse:
3182 pszAudioDriver = "PulseAudio";
3183 break;
3184#endif
3185#ifdef RT_OS_DARWIN
3186 case AudioDriverType_CoreAudio:
3187 pszAudioDriver = "CoreAudio";
3188 break;
3189#endif
3190 default:
3191 pszAudioDriver = "oops";
3192 AssertFailedBreak();
3193 }
3194
3195 unsigned idxAudioLun = 0;
3196
3197 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", idxAudioLun);
3198 i_configAudioDriver(audioAdapter, virtualBox, pMachine, pLunL0, pszAudioDriver);
3199 idxAudioLun++;
3200
3201#ifdef VBOX_WITH_AUDIO_VRDE
3202 /* Insert dummy audio driver to have the LUN configured. */
3203 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", idxAudioLun);
3204 InsertConfigString(pLunL0, "Driver", "AUDIO");
3205 AudioDriverCfg DrvCfgVRDE(pszAudioDevice, 0 /* Instance */, idxAudioLun, "AudioVRDE");
3206 rc = mAudioVRDE->InitializeConfig(&DrvCfgVRDE);
3207 AssertRCStmt(rc, throw ConfigError(__FUNCTION__, rc, "mAudioVRDE->InitializeConfig failed"));
3208 idxAudioLun++;
3209#endif /* VBOX_WITH_AUDIO_VRDE */
3210
3211#ifdef VBOX_WITH_AUDIO_RECORDING
3212 /* Insert dummy audio driver to have the LUN configured. */
3213 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", idxAudioLun);
3214 InsertConfigString(pLunL0, "Driver", "AUDIO");
3215 AudioDriverCfg DrvCfgVideoRec(pszAudioDevice, 0 /* Instance */, idxAudioLun, "AudioVideoRec");
3216 rc = Recording.mAudioRec->InitializeConfig(&DrvCfgVideoRec);
3217 AssertRCStmt(rc, throw ConfigError(__FUNCTION__, rc, "Recording.mAudioRec->InitializeConfig failed"));
3218 idxAudioLun++;
3219#endif /* VBOX_WITH_AUDIO_RECORDING */
3220
3221 if (fDebugEnabled)
3222 {
3223#ifdef VBOX_WITH_AUDIO_DEBUG
3224 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", idxAudioLun);
3225 i_configAudioDriver(audioAdapter, virtualBox, pMachine, pLunL0, "DebugAudio");
3226 idxAudioLun++;
3227#endif /* VBOX_WITH_AUDIO_DEBUG */
3228
3229 /*
3230 * Tweak the logging groups.
3231 */
3232 rc = RTLogGroupSettings(RTLogRelGetDefaultInstance(),
3233 "drv_host_audio.e.l.l2.l3.f"
3234 " drv_audio.e.l.l2.l3.f"
3235 " audio_mixer.e.l.l2.l3.f"
3236 " dev_hda_codec.e.l.l2.l3.f"
3237 " dev_hda.e.l.l2.l3.f"
3238 " dev_ac97.e.l.l2.l3.f"
3239 " dev_sb16.e.l.l2.l3.f");
3240 if (RT_FAILURE(rc))
3241 LogRel(("Audio: Setting debug logging failed, rc=%Rrc\n", rc));
3242 }
3243
3244#ifdef VBOX_WITH_AUDIO_VALIDATIONKIT
3245 if (fVaKitEnabled)
3246 {
3247 /*
3248 * The ValidationKit backend.
3249 */
3250 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", idxAudioLun);
3251 i_configAudioDriver(audioAdapter, virtualBox, pMachine, pLunL0, "ValidationKitAudio");
3252 idxAudioLun++;
3253
3254 LogRel(("Audio: ValidationKit driver active\n"));
3255 }
3256#endif /* VBOX_WITH_AUDIO_VALIDATIONKIT */
3257 }
3258
3259#ifdef VBOX_WITH_SHARED_CLIPBOARD
3260 /*
3261 * Shared Clipboard.
3262 */
3263 {
3264 ClipboardMode_T enmClipboardMode = ClipboardMode_Disabled;
3265 hrc = pMachine->COMGETTER(ClipboardMode)(&enmClipboardMode); H();
3266# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
3267 BOOL fFileTransfersEnabled;
3268 hrc = pMachine->COMGETTER(ClipboardFileTransfersEnabled)(&fFileTransfersEnabled); H();
3269#endif
3270
3271 /* Load the service */
3272 rc = pVMMDev->hgcmLoadService("VBoxSharedClipboard", "VBoxSharedClipboard");
3273 if (RT_SUCCESS(rc))
3274 {
3275 LogRel(("Shared Clipboard: Service loaded\n"));
3276
3277 /* Set initial clipboard mode. */
3278 rc = i_changeClipboardMode(enmClipboardMode);
3279 AssertLogRelMsg(RT_SUCCESS(rc), ("Shared Clipboard: Failed to set initial clipboard mode (%d): rc=%Rrc\n",
3280 enmClipboardMode, rc));
3281
3282 /* Setup the service. */
3283 VBOXHGCMSVCPARM parm;
3284 HGCMSvcSetU32(&parm, !i_useHostClipboard());
3285 rc = pVMMDev->hgcmHostCall("VBoxSharedClipboard", VBOX_SHCL_HOST_FN_SET_HEADLESS, 1, &parm);
3286 AssertLogRelMsg(RT_SUCCESS(rc), ("Shared Clipboard: Failed to set initial headless mode (%RTbool): rc=%Rrc\n",
3287 !i_useHostClipboard(), rc));
3288
3289# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
3290 rc = i_changeClipboardFileTransferMode(RT_BOOL(fFileTransfersEnabled));
3291 AssertLogRelMsg(RT_SUCCESS(rc), ("Shared Clipboard: Failed to set initial file transfers mode (%u): rc=%Rrc\n",
3292 fFileTransfersEnabled, rc));
3293
3294 /** @todo Register area callbacks? (See also deregistration todo in Console::i_powerDown.) */
3295# endif
3296 }
3297 else
3298 LogRel(("Shared Clipboard: Not available, rc=%Rrc\n", rc));
3299 rc = VINF_SUCCESS; /* None of the potential failures above are fatal. */
3300 }
3301#endif /* VBOX_WITH_SHARED_CLIPBOARD */
3302
3303 /*
3304 * HGCM HostChannel.
3305 */
3306 {
3307 Bstr value;
3308 hrc = pMachine->GetExtraData(Bstr("HGCM/HostChannel").raw(),
3309 value.asOutParam());
3310
3311 if ( hrc == S_OK
3312 && value == "1")
3313 {
3314 rc = pVMMDev->hgcmLoadService("VBoxHostChannel", "VBoxHostChannel");
3315 if (RT_FAILURE(rc))
3316 {
3317 LogRel(("VBoxHostChannel is not available, rc=%Rrc\n", rc));
3318 /* That is not a fatal failure. */
3319 rc = VINF_SUCCESS;
3320 }
3321 }
3322 }
3323
3324#ifdef VBOX_WITH_DRAG_AND_DROP
3325 /*
3326 * Drag and Drop.
3327 */
3328 {
3329 DnDMode_T enmMode = DnDMode_Disabled;
3330 hrc = pMachine->COMGETTER(DnDMode)(&enmMode); H();
3331
3332 /* Load the service */
3333 rc = pVMMDev->hgcmLoadService("VBoxDragAndDropSvc", "VBoxDragAndDropSvc");
3334 if (RT_FAILURE(rc))
3335 {
3336 LogRel(("Drag and drop service is not available, rc=%Rrc\n", rc));
3337 /* That is not a fatal failure. */
3338 rc = VINF_SUCCESS;
3339 }
3340 else
3341 {
3342 rc = HGCMHostRegisterServiceExtension(&m_hHgcmSvcExtDragAndDrop, "VBoxDragAndDropSvc",
3343 &GuestDnD::notifyDnDDispatcher,
3344 GuestDnDInst());
3345 if (RT_FAILURE(rc))
3346 Log(("Cannot register VBoxDragAndDropSvc extension, rc=%Rrc\n", rc));
3347 else
3348 {
3349 LogRel(("Drag and drop service loaded\n"));
3350 rc = i_changeDnDMode(enmMode);
3351 }
3352 }
3353 }
3354#endif /* VBOX_WITH_DRAG_AND_DROP */
3355
3356 /*
3357 * ACPI
3358 */
3359 BOOL fACPI;
3360 hrc = biosSettings->COMGETTER(ACPIEnabled)(&fACPI); H();
3361 if (fACPI)
3362 {
3363 /* Always show the CPU leafs when we have multiple VCPUs or when the IO-APIC is enabled.
3364 * The Windows SMP kernel needs a CPU leaf or else its idle loop will burn cpu cycles; the
3365 * intelppm driver refuses to register an idle state handler.
3366 * Always show CPU leafs for OS X guests. */
3367 BOOL fShowCpu = fOsXGuest;
3368 if (cCpus > 1 || fIOAPIC)
3369 fShowCpu = true;
3370
3371 BOOL fCpuHotPlug;
3372 hrc = pMachine->COMGETTER(CPUHotPlugEnabled)(&fCpuHotPlug); H();
3373
3374 InsertConfigNode(pDevices, "acpi", &pDev);
3375 InsertConfigNode(pDev, "0", &pInst);
3376 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3377 InsertConfigNode(pInst, "Config", &pCfg);
3378 hrc = pBusMgr->assignPCIDevice("acpi", pInst); H();
3379
3380 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
3381
3382 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
3383 InsertConfigInteger(pCfg, "FdcEnabled", fFdcEnabled);
3384 InsertConfigInteger(pCfg, "HpetEnabled", fHPETEnabled);
3385 InsertConfigInteger(pCfg, "SmcEnabled", fSmcEnabled);
3386 InsertConfigInteger(pCfg, "ShowRtc", fShowRtc);
3387 if (fOsXGuest && !llBootNics.empty())
3388 {
3389 BootNic aNic = llBootNics.front();
3390 uint32_t u32NicPCIAddr = (aNic.mPCIAddress.miDevice << 16) | aNic.mPCIAddress.miFn;
3391 InsertConfigInteger(pCfg, "NicPciAddress", u32NicPCIAddr);
3392 }
3393 if (fOsXGuest && fAudioEnabled)
3394 {
3395 PCIBusAddress Address;
3396 if (pBusMgr->findPCIAddress("hda", 0, Address))
3397 {
3398 uint32_t u32AudioPCIAddr = (Address.miDevice << 16) | Address.miFn;
3399 InsertConfigInteger(pCfg, "AudioPciAddress", u32AudioPCIAddr);
3400 }
3401 }
3402 if (fOsXGuest)
3403 {
3404 PCIBusAddress Address;
3405 if (pBusMgr->findPCIAddress("nvme", 0, Address))
3406 {
3407 uint32_t u32NvmePCIAddr = (Address.miDevice << 16) | Address.miFn;
3408 InsertConfigInteger(pCfg, "NvmePciAddress", u32NvmePCIAddr);
3409 }
3410 }
3411 if (iommuType == IommuType_AMD)
3412 {
3413 PCIBusAddress Address;
3414 if (pBusMgr->findPCIAddress("iommu-amd", 0, Address))
3415 {
3416 uint32_t u32IommuAddress = (Address.miDevice << 16) | Address.miFn;
3417 InsertConfigInteger(pCfg, "IommuAmdEnabled", true);
3418 InsertConfigInteger(pCfg, "IommuPciAddress", u32IommuAddress);
3419 if (pBusMgr->findPCIAddress("sb-ioapic", 0, Address))
3420 {
3421 uint32_t const u32SbIoapicAddress = (Address.miDevice << 16) | Address.miFn;
3422 InsertConfigInteger(pCfg, "SbIoApicPciAddress", u32SbIoapicAddress);
3423 }
3424 else
3425 return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
3426 N_("AMD IOMMU is enabled, but the I/O APIC is not assigned a PCI address!"));
3427 }
3428 }
3429 else if (iommuType == IommuType_Intel)
3430 {
3431 PCIBusAddress Address;
3432 if (pBusMgr->findPCIAddress("iommu-intel", 0, Address))
3433 {
3434 uint32_t u32IommuAddress = (Address.miDevice << 16) | Address.miFn;
3435 InsertConfigInteger(pCfg, "IommuIntelEnabled", true);
3436 InsertConfigInteger(pCfg, "IommuPciAddress", u32IommuAddress);
3437 if (pBusMgr->findPCIAddress("sb-ioapic", 0, Address))
3438 {
3439 uint32_t const u32SbIoapicAddress = (Address.miDevice << 16) | Address.miFn;
3440 InsertConfigInteger(pCfg, "SbIoApicPciAddress", u32SbIoapicAddress);
3441 }
3442 else
3443 return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
3444 N_("Intel IOMMU is enabled, but the I/O APIC is not assigned a PCI address!"));
3445 }
3446 }
3447
3448 InsertConfigInteger(pCfg, "IocPciAddress", uIocPCIAddress);
3449 if (chipsetType == ChipsetType_ICH9)
3450 {
3451 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
3452 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
3453 /* 64-bit prefetch window root resource:
3454 * Only for ICH9 and if PAE or Long Mode is enabled.
3455 * And only with hardware virtualization (@bugref{5454}). */
3456 if ( (fEnablePAE || fIsGuest64Bit)
3457 && fSupportsHwVirtEx /* HwVirt needs to be supported by the host
3458 otherwise VMM falls back to raw mode */
3459 && fHMEnabled /* HwVirt needs to be enabled in VM config */)
3460 InsertConfigInteger(pCfg, "PciPref64Enabled", 1);
3461 }
3462 InsertConfigInteger(pCfg, "HostBusPciAddress", uHbcPCIAddress);
3463 InsertConfigInteger(pCfg, "ShowCpu", fShowCpu);
3464 InsertConfigInteger(pCfg, "CpuHotPlug", fCpuHotPlug);
3465
3466 InsertConfigInteger(pCfg, "Serial0IoPortBase", auSerialIoPortBase[0]);
3467 InsertConfigInteger(pCfg, "Serial0Irq", auSerialIrq[0]);
3468
3469 InsertConfigInteger(pCfg, "Serial1IoPortBase", auSerialIoPortBase[1]);
3470 InsertConfigInteger(pCfg, "Serial1Irq", auSerialIrq[1]);
3471
3472 if (auSerialIoPortBase[2])
3473 {
3474 InsertConfigInteger(pCfg, "Serial2IoPortBase", auSerialIoPortBase[2]);
3475 InsertConfigInteger(pCfg, "Serial2Irq", auSerialIrq[2]);
3476 }
3477
3478 if (auSerialIoPortBase[3])
3479 {
3480 InsertConfigInteger(pCfg, "Serial3IoPortBase", auSerialIoPortBase[3]);
3481 InsertConfigInteger(pCfg, "Serial3Irq", auSerialIrq[3]);
3482 }
3483
3484 InsertConfigInteger(pCfg, "Parallel0IoPortBase", auParallelIoPortBase[0]);
3485 InsertConfigInteger(pCfg, "Parallel0Irq", auParallelIrq[0]);
3486
3487 InsertConfigInteger(pCfg, "Parallel1IoPortBase", auParallelIoPortBase[1]);
3488 InsertConfigInteger(pCfg, "Parallel1Irq", auParallelIrq[1]);
3489
3490 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3491 InsertConfigString(pLunL0, "Driver", "ACPIHost");
3492 InsertConfigNode(pLunL0, "Config", &pCfg);
3493
3494 /* Attach the dummy CPU drivers */
3495 for (ULONG iCpuCurr = 1; iCpuCurr < cCpus; iCpuCurr++)
3496 {
3497 BOOL fCpuAttached = true;
3498
3499 if (fCpuHotPlug)
3500 {
3501 hrc = pMachine->GetCPUStatus(iCpuCurr, &fCpuAttached); H();
3502 }
3503
3504 if (fCpuAttached)
3505 {
3506 InsertConfigNode(pInst, Utf8StrFmt("LUN#%u", iCpuCurr).c_str(), &pLunL0);
3507 InsertConfigString(pLunL0, "Driver", "ACPICpu");
3508 InsertConfigNode(pLunL0, "Config", &pCfg);
3509 }
3510 }
3511 }
3512
3513 /*
3514 * Configure DBGF (Debug(ger) Facility) and DBGC (Debugger Console).
3515 */
3516 {
3517 PCFGMNODE pDbgf;
3518 InsertConfigNode(pRoot, "DBGF", &pDbgf);
3519
3520 /* Paths to search for debug info and such things. */
3521 hrc = pMachine->COMGETTER(SettingsFilePath)(bstr.asOutParam()); H();
3522 Utf8Str strSettingsPath(bstr);
3523 bstr.setNull();
3524 strSettingsPath.stripFilename();
3525 strSettingsPath.append("/");
3526
3527 char szHomeDir[RTPATH_MAX + 1];
3528 int rc2 = RTPathUserHome(szHomeDir, sizeof(szHomeDir) - 1);
3529 if (RT_FAILURE(rc2))
3530 szHomeDir[0] = '\0';
3531 RTPathEnsureTrailingSeparator(szHomeDir, sizeof(szHomeDir));
3532
3533
3534 Utf8Str strPath;
3535 strPath.append(strSettingsPath).append("debug/;");
3536 strPath.append(strSettingsPath).append(";");
3537 strPath.append("cache*").append(strSettingsPath).append("dbgcache/;"); /* handy for symlinking to actual cache */
3538 strPath.append(szHomeDir);
3539
3540 InsertConfigString(pDbgf, "Path", strPath.c_str());
3541
3542 /* Tracing configuration. */
3543 BOOL fTracingEnabled;
3544 hrc = pMachine->COMGETTER(TracingEnabled)(&fTracingEnabled); H();
3545 if (fTracingEnabled)
3546 InsertConfigInteger(pDbgf, "TracingEnabled", 1);
3547
3548 hrc = pMachine->COMGETTER(TracingConfig)(bstr.asOutParam()); H();
3549 if (fTracingEnabled)
3550 InsertConfigString(pDbgf, "TracingConfig", bstr);
3551
3552 BOOL fAllowTracingToAccessVM;
3553 hrc = pMachine->COMGETTER(AllowTracingToAccessVM)(&fAllowTracingToAccessVM); H();
3554 if (fAllowTracingToAccessVM)
3555 InsertConfigInteger(pPDM, "AllowTracingToAccessVM", 1);
3556
3557 /* Debugger console config. */
3558 PCFGMNODE pDbgc;
3559 InsertConfigNode(pRoot, "DBGC", &pDbgc);
3560
3561 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
3562 Utf8Str strVBoxHome = bstr;
3563 bstr.setNull();
3564 if (strVBoxHome.isNotEmpty())
3565 strVBoxHome.append("/");
3566 else
3567 {
3568 strVBoxHome = szHomeDir;
3569 strVBoxHome.append("/.vbox");
3570 }
3571
3572 Utf8Str strFile(strVBoxHome);
3573 strFile.append("dbgc-history");
3574 InsertConfigString(pDbgc, "HistoryFile", strFile);
3575
3576 strFile = strSettingsPath;
3577 strFile.append("dbgc-init");
3578 InsertConfigString(pDbgc, "LocalInitScript", strFile);
3579
3580 strFile = strVBoxHome;
3581 strFile.append("dbgc-init");
3582 InsertConfigString(pDbgc, "GlobalInitScript", strFile);
3583 }
3584 }
3585 catch (ConfigError &x)
3586 {
3587 // InsertConfig threw something:
3588 VMR3SetError(pUVM, x.m_vrc, RT_SRC_POS, "Caught ConfigError: %Rrc - %s", x.m_vrc, x.what());
3589 return x.m_vrc;
3590 }
3591 catch (HRESULT hrcXcpt)
3592 {
3593 AssertLogRelMsgFailedReturn(("hrc=%Rhrc\n", hrcXcpt), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
3594 }
3595
3596#ifdef VBOX_WITH_EXTPACK
3597 /*
3598 * Call the extension pack hooks if everything went well thus far.
3599 */
3600 if (RT_SUCCESS(rc))
3601 {
3602 pAlock->release();
3603 rc = mptrExtPackManager->i_callAllVmConfigureVmmHooks(this, pVM);
3604 pAlock->acquire();
3605 }
3606#endif
3607
3608 /*
3609 * Apply the CFGM overlay.
3610 */
3611 if (RT_SUCCESS(rc))
3612 rc = i_configCfgmOverlay(pRoot, virtualBox, pMachine);
3613
3614 /*
3615 * Dump all extradata API settings tweaks, both global and per VM.
3616 */
3617 if (RT_SUCCESS(rc))
3618 rc = i_configDumpAPISettingsTweaks(virtualBox, pMachine);
3619
3620#undef H
3621
3622 pAlock->release(); /* Avoid triggering the lock order inversion check. */
3623
3624 /*
3625 * Register VM state change handler.
3626 */
3627 int rc2 = VMR3AtStateRegister(pUVM, Console::i_vmstateChangeCallback, this);
3628 AssertRC(rc2);
3629 if (RT_SUCCESS(rc))
3630 rc = rc2;
3631
3632 /*
3633 * Register VM runtime error handler.
3634 */
3635 rc2 = VMR3AtRuntimeErrorRegister(pUVM, Console::i_atVMRuntimeErrorCallback, this);
3636 AssertRC(rc2);
3637 if (RT_SUCCESS(rc))
3638 rc = rc2;
3639
3640 pAlock->acquire();
3641
3642 LogFlowFunc(("vrc = %Rrc\n", rc));
3643 LogFlowFuncLeave();
3644
3645 return rc;
3646}
3647
3648/**
3649 * Configures an audio driver via CFGM by getting (optional) values from extra data.
3650 *
3651 * @param pAudioAdapter Pointer to audio adapter instance. Needed for the driver's input / output configuration.
3652 * @param pVirtualBox Pointer to IVirtualBox instance.
3653 * @param pMachine Pointer to IMachine instance.
3654 * @param pLUN Pointer to CFGM node of LUN (the driver) to configure.
3655 * @param pszDrvName Name of the driver to configure.
3656 *
3657 * @throws ConfigError or HRESULT on if there is trouble.
3658 */
3659void Console::i_configAudioDriver(IAudioAdapter *pAudioAdapter, IVirtualBox *pVirtualBox, IMachine *pMachine,
3660 PCFGMNODE pLUN, const char *pszDrvName)
3661{
3662#define H() AssertLogRelMsgStmt(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), \
3663 throw ConfigError(__FUNCTION__, VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR, "line: " RT_XSTR(__LINE__)))
3664
3665 HRESULT hrc;
3666
3667 BOOL fAudioEnabledIn = FALSE;
3668 hrc = pAudioAdapter->COMGETTER(EnabledIn)(&fAudioEnabledIn); H();
3669 BOOL fAudioEnabledOut = FALSE;
3670 hrc = pAudioAdapter->COMGETTER(EnabledOut)(&fAudioEnabledOut); H();
3671
3672 InsertConfigString(pLUN, "Driver", "AUDIO");
3673
3674 PCFGMNODE pCfg;
3675 InsertConfigNode(pLUN, "Config", &pCfg);
3676 InsertConfigString(pCfg, "DriverName", pszDrvName);
3677 InsertConfigInteger(pCfg, "InputEnabled", fAudioEnabledIn);
3678 InsertConfigInteger(pCfg, "OutputEnabled", fAudioEnabledOut);
3679
3680 Utf8Str strTmp;
3681 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/Audio/Debug/Enabled", &strTmp);
3682 const uint64_t fDebugEnabled = strTmp.equalsIgnoreCase("true") || strTmp.equalsIgnoreCase("1");
3683 if (fDebugEnabled)
3684 {
3685 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
3686
3687 Utf8Str strDebugPathOut;
3688 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/Audio/Debug/PathOut", &strDebugPathOut);
3689 InsertConfigString(pCfg, "DebugPathOut", strDebugPathOut.c_str());
3690 }
3691
3692 /*
3693 * PCM input parameters (playback + recording).
3694 * We have host driver specific ones as: VBoxInternal2/Audio/<DrvName>/<Value>
3695 * And global ones for all host drivers: VBoxInternal2/Audio/<Value>
3696 */
3697 for (unsigned iDir = 0; iDir < 2; iDir++)
3698 {
3699 static const struct
3700 {
3701 const char *pszExtraName;
3702 const char *pszCfgmName;
3703 } s_aToCopy[] =
3704 { /* PCM parameters: */
3705 { "PCMSampleBit", "PCMSampleBit" },
3706 { "PCMSampleHz", "PCMSampleHz" },
3707 { "PCMSampleSigned", "PCMSampleSigned" },
3708 { "PCMSampleSwapEndian", "PCMSampleSwapEndian" },
3709 { "PCMSampleChannels", "PCMSampleChannels" },
3710 /* Buffering stuff: */
3711 { "PeriodSizeMs", "PeriodSizeMs" },
3712 { "BufferSizeMs", "BufferSizeMs" },
3713 { "PreBufferSizeMs", "PreBufferSizeMs" },
3714 };
3715
3716 PCFGMNODE pDirNode = NULL;
3717 const char *pszDir = iDir == 0 ? "In" : "Out";
3718 for (size_t i = 0; i < RT_ELEMENTS(s_aToCopy); i++)
3719 {
3720 char szExtra[128];
3721 RTStrPrintf(szExtra, sizeof(szExtra), "VBoxInternal2/Audio/%s/%s%s", pszDrvName, s_aToCopy[i].pszExtraName, pszDir);
3722 GetExtraDataBoth(pVirtualBox, pMachine, szExtra, &strTmp); /* throws hrc */
3723 if (strTmp.isEmpty())
3724 {
3725 RTStrPrintf(szExtra, sizeof(szExtra), "VBoxInternal2/Audio/%s%s", s_aToCopy[i].pszExtraName, pszDir);
3726 GetExtraDataBoth(pVirtualBox, pMachine, szExtra, &strTmp);
3727 if (strTmp.isEmpty())
3728 continue;
3729 }
3730
3731 uint32_t uValue;
3732 int vrc = RTStrToUInt32Full(strTmp.c_str(), 0, &uValue);
3733 if (RT_SUCCESS(vrc))
3734 {
3735 if (!pDirNode)
3736 InsertConfigNode(pCfg, pszDir, &pDirNode);
3737 InsertConfigInteger(pDirNode, s_aToCopy[i].pszCfgmName, uValue);
3738 }
3739 else
3740 LogRel(("Ignoring malformed 32-bit unsigned integer config value '%s' = '%s': %Rrc\n", szExtra, strTmp.c_str(), vrc));
3741 }
3742 }
3743
3744 PCFGMNODE pLunL1;
3745 InsertConfigNode(pLUN, "AttachedDriver", &pLunL1);
3746 InsertConfigString(pLunL1, "Driver", pszDrvName);
3747 InsertConfigNode(pLunL1, "Config", &pCfg);
3748
3749#ifdef RT_OS_WINDOWS
3750 if (strcmp(pszDrvName, "HostAudioWas") == 0)
3751 {
3752 Bstr bstrTmp;
3753 hrc = pMachine->COMGETTER(Id)(bstrTmp.asOutParam()); H();
3754 InsertConfigString(pCfg, "VmUuid", bstrTmp);
3755 }
3756#endif
3757
3758#if defined(RT_OS_WINDOWS) || defined(RT_OS_LINUX)
3759 if ( strcmp(pszDrvName, "HostAudioWas") == 0
3760 || strcmp(pszDrvName, "PulseAudio") == 0)
3761 {
3762 Bstr bstrTmp;
3763 hrc = pMachine->COMGETTER(Name)(bstrTmp.asOutParam()); H();
3764 InsertConfigString(pCfg, "VmName", bstrTmp);
3765 }
3766#endif
3767
3768 LogFlowFunc(("szDrivName=%s\n", pszDrvName));
3769
3770#undef H
3771}
3772
3773/**
3774 * Applies the CFGM overlay as specified by VBoxInternal/XXX extra data
3775 * values.
3776 *
3777 * @returns VBox status code.
3778 * @param pRoot The root of the configuration tree.
3779 * @param pVirtualBox Pointer to the IVirtualBox interface.
3780 * @param pMachine Pointer to the IMachine interface.
3781 */
3782/* static */
3783int Console::i_configCfgmOverlay(PCFGMNODE pRoot, IVirtualBox *pVirtualBox, IMachine *pMachine)
3784{
3785 /*
3786 * CFGM overlay handling.
3787 *
3788 * Here we check the extra data entries for CFGM values
3789 * and create the nodes and insert the values on the fly. Existing
3790 * values will be removed and reinserted. CFGM is typed, so by default
3791 * we will guess whether it's a string or an integer (byte arrays are
3792 * not currently supported). It's possible to override this autodetection
3793 * by adding "string:", "integer:" or "bytes:" (future).
3794 *
3795 * We first perform a run on global extra data, then on the machine
3796 * extra data to support global settings with local overrides.
3797 */
3798 int rc = VINF_SUCCESS;
3799 bool fFirst = true;
3800 try
3801 {
3802 /** @todo add support for removing nodes and byte blobs. */
3803 /*
3804 * Get the next key
3805 */
3806 SafeArray<BSTR> aGlobalExtraDataKeys;
3807 SafeArray<BSTR> aMachineExtraDataKeys;
3808 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
3809 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
3810
3811 // remember the no. of global values so we can call the correct method below
3812 size_t cGlobalValues = aGlobalExtraDataKeys.size();
3813
3814 hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
3815 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
3816
3817 // build a combined list from global keys...
3818 std::list<Utf8Str> llExtraDataKeys;
3819
3820 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); ++i)
3821 llExtraDataKeys.push_back(Utf8Str(aGlobalExtraDataKeys[i]));
3822 // ... and machine keys
3823 for (size_t i = 0; i < aMachineExtraDataKeys.size(); ++i)
3824 llExtraDataKeys.push_back(Utf8Str(aMachineExtraDataKeys[i]));
3825
3826 size_t i2 = 0;
3827 for (std::list<Utf8Str>::const_iterator it = llExtraDataKeys.begin();
3828 it != llExtraDataKeys.end();
3829 ++it, ++i2)
3830 {
3831 const Utf8Str &strKey = *it;
3832
3833 /*
3834 * We only care about keys starting with "VBoxInternal/" (skip "G:" or "M:")
3835 */
3836 if (!strKey.startsWith("VBoxInternal/"))
3837 continue;
3838
3839 const char *pszExtraDataKey = strKey.c_str() + sizeof("VBoxInternal/") - 1;
3840
3841 // get the value
3842 Bstr bstrExtraDataValue;
3843 if (i2 < cGlobalValues)
3844 // this is still one of the global values:
3845 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
3846 bstrExtraDataValue.asOutParam());
3847 else
3848 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
3849 bstrExtraDataValue.asOutParam());
3850 if (FAILED(hrc))
3851 LogRel(("Warning: Cannot get extra data key %s, rc = %Rhrc\n", strKey.c_str(), hrc));
3852
3853 if (fFirst)
3854 {
3855 fFirst = false;
3856 LogRel(("Extradata overrides:\n"));
3857 }
3858 LogRel((" %s=\"%ls\"%s\n", strKey.c_str(), bstrExtraDataValue.raw(), i2 < cGlobalValues ? " (global)" : ""));
3859
3860 /*
3861 * The key will be in the format "Node1/Node2/Value" or simply "Value".
3862 * Split the two and get the node, delete the value and create the node
3863 * if necessary.
3864 */
3865 PCFGMNODE pNode;
3866 const char *pszCFGMValueName = strrchr(pszExtraDataKey, '/');
3867 if (pszCFGMValueName)
3868 {
3869 /* terminate the node and advance to the value (Utf8Str might not
3870 offically like this but wtf) */
3871 *(char *)pszCFGMValueName = '\0';
3872 ++pszCFGMValueName;
3873
3874 /* does the node already exist? */
3875 pNode = CFGMR3GetChild(pRoot, pszExtraDataKey);
3876 if (pNode)
3877 CFGMR3RemoveValue(pNode, pszCFGMValueName);
3878 else
3879 {
3880 /* create the node */
3881 rc = CFGMR3InsertNode(pRoot, pszExtraDataKey, &pNode);
3882 if (RT_FAILURE(rc))
3883 {
3884 AssertLogRelMsgRC(rc, ("failed to insert node '%s'\n", pszExtraDataKey));
3885 continue;
3886 }
3887 Assert(pNode);
3888 }
3889 }
3890 else
3891 {
3892 /* root value (no node path). */
3893 pNode = pRoot;
3894 pszCFGMValueName = pszExtraDataKey;
3895 pszExtraDataKey--;
3896 CFGMR3RemoveValue(pNode, pszCFGMValueName);
3897 }
3898
3899 /*
3900 * Now let's have a look at the value.
3901 * Empty strings means that we should remove the value, which we've
3902 * already done above.
3903 */
3904 Utf8Str strCFGMValueUtf8(bstrExtraDataValue);
3905 if (!strCFGMValueUtf8.isEmpty())
3906 {
3907 uint64_t u64Value;
3908
3909 /* check for type prefix first. */
3910 if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("string:")))
3911 InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8.c_str() + sizeof("string:") - 1);
3912 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("integer:")))
3913 {
3914 rc = RTStrToUInt64Full(strCFGMValueUtf8.c_str() + sizeof("integer:") - 1, 0, &u64Value);
3915 if (RT_SUCCESS(rc))
3916 rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
3917 }
3918 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("bytes:")))
3919 {
3920 char const *pszBase64 = strCFGMValueUtf8.c_str() + sizeof("bytes:") - 1;
3921 ssize_t cbValue = RTBase64DecodedSize(pszBase64, NULL);
3922 if (cbValue > 0)
3923 {
3924 void *pvBytes = RTMemTmpAlloc(cbValue);
3925 if (pvBytes)
3926 {
3927 rc = RTBase64Decode(pszBase64, pvBytes, cbValue, NULL, NULL);
3928 if (RT_SUCCESS(rc))
3929 rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, pvBytes, cbValue);
3930 RTMemTmpFree(pvBytes);
3931 }
3932 else
3933 rc = VERR_NO_TMP_MEMORY;
3934 }
3935 else if (cbValue == 0)
3936 rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, NULL, 0);
3937 else
3938 rc = VERR_INVALID_BASE64_ENCODING;
3939 }
3940 /* auto detect type. */
3941 else if (RT_SUCCESS(RTStrToUInt64Full(strCFGMValueUtf8.c_str(), 0, &u64Value)))
3942 rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
3943 else
3944 InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8);
3945 AssertLogRelMsgRCBreak(rc, ("failed to insert CFGM value '%s' to key '%s'\n",
3946 strCFGMValueUtf8.c_str(), pszExtraDataKey));
3947 }
3948 }
3949 }
3950 catch (ConfigError &x)
3951 {
3952 // InsertConfig threw something:
3953 return x.m_vrc;
3954 }
3955 return rc;
3956}
3957
3958/**
3959 * Dumps the API settings tweaks as specified by VBoxInternal2/XXX extra data
3960 * values.
3961 *
3962 * @returns VBox status code.
3963 * @param pVirtualBox Pointer to the IVirtualBox interface.
3964 * @param pMachine Pointer to the IMachine interface.
3965 */
3966/* static */
3967int Console::i_configDumpAPISettingsTweaks(IVirtualBox *pVirtualBox, IMachine *pMachine)
3968{
3969 {
3970 SafeArray<BSTR> aGlobalExtraDataKeys;
3971 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
3972 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
3973 bool hasKey = false;
3974 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); i++)
3975 {
3976 Utf8Str strKey(aGlobalExtraDataKeys[i]);
3977 if (!strKey.startsWith("VBoxInternal2/"))
3978 continue;
3979
3980 Bstr bstrValue;
3981 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
3982 bstrValue.asOutParam());
3983 if (FAILED(hrc))
3984 continue;
3985 if (!hasKey)
3986 LogRel(("Global extradata API settings:\n"));
3987 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
3988 hasKey = true;
3989 }
3990 }
3991
3992 {
3993 SafeArray<BSTR> aMachineExtraDataKeys;
3994 HRESULT hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
3995 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
3996 bool hasKey = false;
3997 for (size_t i = 0; i < aMachineExtraDataKeys.size(); i++)
3998 {
3999 Utf8Str strKey(aMachineExtraDataKeys[i]);
4000 if (!strKey.startsWith("VBoxInternal2/"))
4001 continue;
4002
4003 Bstr bstrValue;
4004 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
4005 bstrValue.asOutParam());
4006 if (FAILED(hrc))
4007 continue;
4008 if (!hasKey)
4009 LogRel(("Per-VM extradata API settings:\n"));
4010 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
4011 hasKey = true;
4012 }
4013 }
4014
4015 return VINF_SUCCESS;
4016}
4017
4018int Console::i_configGraphicsController(PCFGMNODE pDevices,
4019 const GraphicsControllerType_T enmGraphicsController,
4020 BusAssignmentManager *pBusMgr,
4021 const ComPtr<IMachine> &ptrMachine,
4022 const ComPtr<IGraphicsAdapter> &ptrGraphicsAdapter,
4023 const ComPtr<IBIOSSettings> &ptrBiosSettings,
4024 bool fHMEnabled)
4025{
4026 // InsertConfig* throws
4027 try
4028 {
4029 PCFGMNODE pDev, pInst, pCfg, pLunL0;
4030 HRESULT hrc;
4031 Bstr bstr;
4032 const char *pcszDevice = "vga";
4033
4034#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4035 InsertConfigNode(pDevices, pcszDevice, &pDev);
4036 InsertConfigNode(pDev, "0", &pInst);
4037 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
4038
4039 hrc = pBusMgr->assignPCIDevice(pcszDevice, pInst); H();
4040 InsertConfigNode(pInst, "Config", &pCfg);
4041 ULONG cVRamMBs;
4042 hrc = ptrGraphicsAdapter->COMGETTER(VRAMSize)(&cVRamMBs); H();
4043 InsertConfigInteger(pCfg, "VRamSize", cVRamMBs * _1M);
4044 ULONG cMonitorCount;
4045 hrc = ptrGraphicsAdapter->COMGETTER(MonitorCount)(&cMonitorCount); H();
4046 InsertConfigInteger(pCfg, "MonitorCount", cMonitorCount);
4047#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
4048 InsertConfigInteger(pCfg, "R0Enabled", fHMEnabled);
4049#else
4050 NOREF(fHMEnabled);
4051#endif
4052 BOOL f3DEnabled;
4053 hrc = ptrGraphicsAdapter->COMGETTER(Accelerate3DEnabled)(&f3DEnabled); H();
4054 InsertConfigInteger(pCfg, "3DEnabled", f3DEnabled);
4055
4056 i_attachStatusDriver(pInst, DeviceType_Graphics3D, 0, 0, NULL, NULL, NULL, 0);
4057
4058#ifdef VBOX_WITH_VMSVGA
4059 if ( enmGraphicsController == GraphicsControllerType_VMSVGA
4060 || enmGraphicsController == GraphicsControllerType_VBoxSVGA)
4061 {
4062 InsertConfigInteger(pCfg, "VMSVGAEnabled", true);
4063 if (enmGraphicsController == GraphicsControllerType_VMSVGA)
4064 {
4065 InsertConfigInteger(pCfg, "VMSVGAPciBarLayout", true);
4066 InsertConfigInteger(pCfg, "VMSVGAPciId", true);
4067 }
4068# ifdef VBOX_WITH_VMSVGA3D
4069 InsertConfigInteger(pCfg, "VMSVGA3dEnabled", f3DEnabled);
4070# else
4071 LogRel(("VMSVGA3d not available in this build!\n"));
4072# endif /* VBOX_WITH_VMSVGA3D */
4073 }
4074#else
4075 RT_NOREF(enmGraphicsController);
4076#endif /* VBOX_WITH_VMSVGA */
4077
4078 /* Custom VESA mode list */
4079 unsigned cModes = 0;
4080 for (unsigned iMode = 1; iMode <= 16; ++iMode)
4081 {
4082 char szExtraDataKey[sizeof("CustomVideoModeXX")];
4083 RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%u", iMode);
4084 hrc = ptrMachine->GetExtraData(Bstr(szExtraDataKey).raw(), bstr.asOutParam()); H();
4085 if (bstr.isEmpty())
4086 break;
4087 InsertConfigString(pCfg, szExtraDataKey, bstr);
4088 ++cModes;
4089 }
4090 InsertConfigInteger(pCfg, "CustomVideoModes", cModes);
4091
4092 /* VESA height reduction */
4093 ULONG ulHeightReduction;
4094 IFramebuffer *pFramebuffer = NULL;
4095 hrc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
4096 if (SUCCEEDED(hrc) && pFramebuffer)
4097 {
4098 hrc = pFramebuffer->COMGETTER(HeightReduction)(&ulHeightReduction); H();
4099 pFramebuffer->Release();
4100 pFramebuffer = NULL;
4101 }
4102 else
4103 {
4104 /* If framebuffer is not available, there is no height reduction. */
4105 ulHeightReduction = 0;
4106 }
4107 InsertConfigInteger(pCfg, "HeightReduction", ulHeightReduction);
4108
4109 /*
4110 * BIOS logo
4111 */
4112 BOOL fFadeIn;
4113 hrc = ptrBiosSettings->COMGETTER(LogoFadeIn)(&fFadeIn); H();
4114 InsertConfigInteger(pCfg, "FadeIn", fFadeIn ? 1 : 0);
4115 BOOL fFadeOut;
4116 hrc = ptrBiosSettings->COMGETTER(LogoFadeOut)(&fFadeOut); H();
4117 InsertConfigInteger(pCfg, "FadeOut", fFadeOut ? 1: 0);
4118 ULONG logoDisplayTime;
4119 hrc = ptrBiosSettings->COMGETTER(LogoDisplayTime)(&logoDisplayTime); H();
4120 InsertConfigInteger(pCfg, "LogoTime", logoDisplayTime);
4121 Bstr logoImagePath;
4122 hrc = ptrBiosSettings->COMGETTER(LogoImagePath)(logoImagePath.asOutParam()); H();
4123 InsertConfigString(pCfg, "LogoFile", Utf8Str(!logoImagePath.isEmpty() ? logoImagePath : "") );
4124
4125 /*
4126 * Boot menu
4127 */
4128 BIOSBootMenuMode_T eBootMenuMode;
4129 int iShowBootMenu;
4130 hrc = ptrBiosSettings->COMGETTER(BootMenuMode)(&eBootMenuMode); H();
4131 switch (eBootMenuMode)
4132 {
4133 case BIOSBootMenuMode_Disabled: iShowBootMenu = 0; break;
4134 case BIOSBootMenuMode_MenuOnly: iShowBootMenu = 1; break;
4135 default: iShowBootMenu = 2; break;
4136 }
4137 InsertConfigInteger(pCfg, "ShowBootMenu", iShowBootMenu);
4138
4139 /* Attach the display. */
4140 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4141 InsertConfigString(pLunL0, "Driver", "MainDisplay");
4142 InsertConfigNode(pLunL0, "Config", &pCfg);
4143 Display *pDisplay = mDisplay;
4144 InsertConfigInteger(pCfg, "Object", (uintptr_t)pDisplay);
4145 }
4146 catch (ConfigError &x)
4147 {
4148 // InsertConfig threw something:
4149 return x.m_vrc;
4150 }
4151
4152#undef H
4153
4154 return VINF_SUCCESS;
4155}
4156
4157
4158/**
4159 * Ellipsis to va_list wrapper for calling setVMRuntimeErrorCallback.
4160 */
4161void Console::i_atVMRuntimeErrorCallbackF(uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)
4162{
4163 va_list va;
4164 va_start(va, pszFormat);
4165 i_atVMRuntimeErrorCallback(NULL, this, fFlags, pszErrorId, pszFormat, va);
4166 va_end(va);
4167}
4168
4169/* XXX introduce RT format specifier */
4170static uint64_t formatDiskSize(uint64_t u64Size, const char **pszUnit)
4171{
4172 if (u64Size > INT64_C(5000)*_1G)
4173 {
4174 *pszUnit = "TB";
4175 return u64Size / _1T;
4176 }
4177 else if (u64Size > INT64_C(5000)*_1M)
4178 {
4179 *pszUnit = "GB";
4180 return u64Size / _1G;
4181 }
4182 else
4183 {
4184 *pszUnit = "MB";
4185 return u64Size / _1M;
4186 }
4187}
4188
4189/**
4190 * Checks the location of the given medium for known bugs affecting the usage
4191 * of the host I/O cache setting.
4192 *
4193 * @returns VBox status code.
4194 * @param pMedium The medium to check.
4195 * @param pfUseHostIOCache Where to store the suggested host I/O cache setting.
4196 */
4197int Console::i_checkMediumLocation(IMedium *pMedium, bool *pfUseHostIOCache)
4198{
4199#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4200 /*
4201 * Some sanity checks.
4202 */
4203 RT_NOREF(pfUseHostIOCache);
4204 ComPtr<IMediumFormat> pMediumFormat;
4205 HRESULT hrc = pMedium->COMGETTER(MediumFormat)(pMediumFormat.asOutParam()); H();
4206 ULONG uCaps = 0;
4207 com::SafeArray <MediumFormatCapabilities_T> mediumFormatCap;
4208 hrc = pMediumFormat->COMGETTER(Capabilities)(ComSafeArrayAsOutParam(mediumFormatCap)); H();
4209
4210 for (ULONG j = 0; j < mediumFormatCap.size(); j++)
4211 uCaps |= mediumFormatCap[j];
4212
4213 if (uCaps & MediumFormatCapabilities_File)
4214 {
4215 Bstr strFile;
4216 hrc = pMedium->COMGETTER(Location)(strFile.asOutParam()); H();
4217 Utf8Str utfFile = Utf8Str(strFile);
4218 Bstr strSnap;
4219 ComPtr<IMachine> pMachine = i_machine();
4220 hrc = pMachine->COMGETTER(SnapshotFolder)(strSnap.asOutParam()); H();
4221 Utf8Str utfSnap = Utf8Str(strSnap);
4222 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
4223 RTFSTYPE enmFsTypeSnap = RTFSTYPE_UNKNOWN;
4224 int rc2 = RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
4225 AssertMsgRCReturn(rc2, ("Querying the file type of '%s' failed!\n", utfFile.c_str()), rc2);
4226 /* Ignore the error code. On error, the file system type is still 'unknown' so
4227 * none of the following paths are taken. This can happen for new VMs which
4228 * still don't have a snapshot folder. */
4229 (void)RTFsQueryType(utfSnap.c_str(), &enmFsTypeSnap);
4230 if (!mfSnapshotFolderDiskTypeShown)
4231 {
4232 LogRel(("File system of '%s' (snapshots) is %s\n",
4233 utfSnap.c_str(), RTFsTypeName(enmFsTypeSnap)));
4234 mfSnapshotFolderDiskTypeShown = true;
4235 }
4236 LogRel(("File system of '%s' is %s\n", utfFile.c_str(), RTFsTypeName(enmFsTypeFile)));
4237 LONG64 i64Size;
4238 hrc = pMedium->COMGETTER(LogicalSize)(&i64Size); H();
4239#ifdef RT_OS_WINDOWS
4240 if ( enmFsTypeFile == RTFSTYPE_FAT
4241 && i64Size >= _4G)
4242 {
4243 const char *pszUnit;
4244 uint64_t u64Print = formatDiskSize((uint64_t)i64Size, &pszUnit);
4245 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
4246 N_("The medium '%ls' has a logical size of %RU64%s "
4247 "but the file system the medium is located on seems "
4248 "to be FAT(32) which cannot handle files bigger than 4GB.\n"
4249 "We strongly recommend to put all your virtual disk images and "
4250 "the snapshot folder onto an NTFS partition"),
4251 strFile.raw(), u64Print, pszUnit);
4252 }
4253#else /* !RT_OS_WINDOWS */
4254 if ( enmFsTypeFile == RTFSTYPE_FAT
4255 || enmFsTypeFile == RTFSTYPE_EXT
4256 || enmFsTypeFile == RTFSTYPE_EXT2
4257 || enmFsTypeFile == RTFSTYPE_EXT3
4258 || enmFsTypeFile == RTFSTYPE_EXT4)
4259 {
4260 RTFILE file;
4261 int rc = RTFileOpen(&file, utfFile.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
4262 if (RT_SUCCESS(rc))
4263 {
4264 RTFOFF maxSize;
4265 /* Careful: This function will work only on selected local file systems! */
4266 rc = RTFileQueryMaxSizeEx(file, &maxSize);
4267 RTFileClose(file);
4268 if ( RT_SUCCESS(rc)
4269 && maxSize > 0
4270 && i64Size > (LONG64)maxSize)
4271 {
4272 const char *pszUnitSiz;
4273 const char *pszUnitMax;
4274 uint64_t u64PrintSiz = formatDiskSize((LONG64)i64Size, &pszUnitSiz);
4275 uint64_t u64PrintMax = formatDiskSize(maxSize, &pszUnitMax);
4276 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected", /* <= not exact but ... */
4277 N_("The medium '%ls' has a logical size of %RU64%s "
4278 "but the file system the medium is located on can "
4279 "only handle files up to %RU64%s in theory.\n"
4280 "We strongly recommend to put all your virtual disk "
4281 "images and the snapshot folder onto a proper "
4282 "file system (e.g. ext3) with a sufficient size"),
4283 strFile.raw(), u64PrintSiz, pszUnitSiz, u64PrintMax, pszUnitMax);
4284 }
4285 }
4286 }
4287#endif /* !RT_OS_WINDOWS */
4288
4289 /*
4290 * Snapshot folder:
4291 * Here we test only for a FAT partition as we had to create a dummy file otherwise
4292 */
4293 if ( enmFsTypeSnap == RTFSTYPE_FAT
4294 && i64Size >= _4G
4295 && !mfSnapshotFolderSizeWarningShown)
4296 {
4297 const char *pszUnit;
4298 uint64_t u64Print = formatDiskSize(i64Size, &pszUnit);
4299 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
4300#ifdef RT_OS_WINDOWS
4301 N_("The snapshot folder of this VM '%ls' seems to be located on "
4302 "a FAT(32) file system. The logical size of the medium '%ls' "
4303 "(%RU64%s) is bigger than the maximum file size this file "
4304 "system can handle (4GB).\n"
4305 "We strongly recommend to put all your virtual disk images and "
4306 "the snapshot folder onto an NTFS partition"),
4307#else
4308 N_("The snapshot folder of this VM '%ls' seems to be located on "
4309 "a FAT(32) file system. The logical size of the medium '%ls' "
4310 "(%RU64%s) is bigger than the maximum file size this file "
4311 "system can handle (4GB).\n"
4312 "We strongly recommend to put all your virtual disk images and "
4313 "the snapshot folder onto a proper file system (e.g. ext3)"),
4314#endif
4315 strSnap.raw(), strFile.raw(), u64Print, pszUnit);
4316 /* Show this particular warning only once */
4317 mfSnapshotFolderSizeWarningShown = true;
4318 }
4319
4320#ifdef RT_OS_LINUX
4321 /*
4322 * Ext4 bug: Check if the host I/O cache is disabled and the disk image is located
4323 * on an ext4 partition.
4324 * This bug apparently applies to the XFS file system as well.
4325 * Linux 2.6.36 is known to be fixed (tested with 2.6.36-rc4).
4326 */
4327
4328 char szOsRelease[128];
4329 int rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOsRelease, sizeof(szOsRelease));
4330 bool fKernelHasODirectBug = RT_FAILURE(rc)
4331 || (RTStrVersionCompare(szOsRelease, "2.6.36-rc4") < 0);
4332
4333 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
4334 && !*pfUseHostIOCache
4335 && fKernelHasODirectBug)
4336 {
4337 if ( enmFsTypeFile == RTFSTYPE_EXT4
4338 || enmFsTypeFile == RTFSTYPE_XFS)
4339 {
4340 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
4341 N_("The host I/O cache for at least one controller is disabled "
4342 "and the medium '%ls' for this VM "
4343 "is located on an %s partition. There is a known Linux "
4344 "kernel bug which can lead to the corruption of the virtual "
4345 "disk image under these conditions.\n"
4346 "Either enable the host I/O cache permanently in the VM "
4347 "settings or put the disk image and the snapshot folder "
4348 "onto a different file system.\n"
4349 "The host I/O cache will now be enabled for this medium"),
4350 strFile.raw(), enmFsTypeFile == RTFSTYPE_EXT4 ? "ext4" : "xfs");
4351 *pfUseHostIOCache = true;
4352 }
4353 else if ( ( enmFsTypeSnap == RTFSTYPE_EXT4
4354 || enmFsTypeSnap == RTFSTYPE_XFS)
4355 && !mfSnapshotFolderExt4WarningShown)
4356 {
4357 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
4358 N_("The host I/O cache for at least one controller is disabled "
4359 "and the snapshot folder for this VM "
4360 "is located on an %s partition. There is a known Linux "
4361 "kernel bug which can lead to the corruption of the virtual "
4362 "disk image under these conditions.\n"
4363 "Either enable the host I/O cache permanently in the VM "
4364 "settings or put the disk image and the snapshot folder "
4365 "onto a different file system.\n"
4366 "The host I/O cache will now be enabled for this medium"),
4367 enmFsTypeSnap == RTFSTYPE_EXT4 ? "ext4" : "xfs");
4368 *pfUseHostIOCache = true;
4369 mfSnapshotFolderExt4WarningShown = true;
4370 }
4371 }
4372
4373 /*
4374 * 2.6.18 bug: Check if the host I/O cache is disabled and the host is running
4375 * Linux 2.6.18. See @bugref{8690}. Apparently the same problem as
4376 * documented in https://lkml.org/lkml/2007/2/1/14. We saw such
4377 * kernel oopses on Linux 2.6.18-416.el5. We don't know when this
4378 * was fixed but we _know_ that 2.6.18 EL5 kernels are affected.
4379 */
4380 bool fKernelAsyncUnreliable = RT_FAILURE(rc)
4381 || (RTStrVersionCompare(szOsRelease, "2.6.19") < 0);
4382 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
4383 && !*pfUseHostIOCache
4384 && fKernelAsyncUnreliable)
4385 {
4386 i_atVMRuntimeErrorCallbackF(0, "Linux2618TooOld",
4387 N_("The host I/O cache for at least one controller is disabled. "
4388 "There is a known Linux kernel bug which can lead to kernel "
4389 "oopses under heavy load. To our knowledge this bug affects "
4390 "all 2.6.18 kernels.\n"
4391 "Either enable the host I/O cache permanently in the VM "
4392 "settings or switch to a newer host kernel.\n"
4393 "The host I/O cache will now be enabled for this medium"));
4394 *pfUseHostIOCache = true;
4395 }
4396#endif
4397 }
4398#undef H
4399
4400 return VINF_SUCCESS;
4401}
4402
4403/**
4404 * Unmounts the specified medium from the specified device.
4405 *
4406 * @returns VBox status code.
4407 * @param pUVM The usermode VM handle.
4408 * @param enmBus The storage bus.
4409 * @param enmDevType The device type.
4410 * @param pcszDevice The device emulation.
4411 * @param uInstance Instance of the device.
4412 * @param uLUN The LUN on the device.
4413 * @param fForceUnmount Whether to force unmounting.
4414 */
4415int Console::i_unmountMediumFromGuest(PUVM pUVM, StorageBus_T enmBus, DeviceType_T enmDevType,
4416 const char *pcszDevice, unsigned uInstance, unsigned uLUN,
4417 bool fForceUnmount)
4418{
4419 /* Unmount existing media only for floppy and DVD drives. */
4420 int rc = VINF_SUCCESS;
4421 PPDMIBASE pBase;
4422 if (enmBus == StorageBus_USB)
4423 rc = PDMR3UsbQueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
4424 else if ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI || enmBus == StorageBus_VirtioSCSI)
4425 || (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD))
4426 rc = PDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
4427 else /* IDE or Floppy */
4428 rc = PDMR3QueryLun(pUVM, pcszDevice, uInstance, uLUN, &pBase);
4429
4430 if (RT_FAILURE(rc))
4431 {
4432 if (rc == VERR_PDM_LUN_NOT_FOUND || rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4433 rc = VINF_SUCCESS;
4434 AssertRC(rc);
4435 }
4436 else
4437 {
4438 PPDMIMOUNT pIMount = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMOUNT);
4439 AssertReturn(pIMount, VERR_INVALID_POINTER);
4440
4441 /* Unmount the media (but do not eject the medium!) */
4442 rc = pIMount->pfnUnmount(pIMount, fForceUnmount, false /*=fEject*/);
4443 if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
4444 rc = VINF_SUCCESS;
4445 /* for example if the medium is locked */
4446 else if (RT_FAILURE(rc))
4447 return rc;
4448 }
4449
4450 return rc;
4451}
4452
4453/**
4454 * Removes the currently attached medium driver form the specified device
4455 * taking care of the controlelr specific configs wrt. to the attached driver chain.
4456 *
4457 * @returns VBox status code.
4458 * @param pCtlInst The controler instance node in the CFGM tree.
4459 * @param pcszDevice The device name.
4460 * @param uInstance The device instance.
4461 * @param uLUN The device LUN.
4462 * @param enmBus The storage bus.
4463 * @param fAttachDetach Flag whether this is a change while the VM is running
4464 * @param fHotplug Flag whether the guest should be notified about the device change.
4465 * @param fForceUnmount Flag whether to force unmounting the medium even if it is locked.
4466 * @param pUVM The usermode VM handle.
4467 * @param enmDevType The device type.
4468 * @param ppLunL0 Where to store the node to attach the new config to on success.
4469 */
4470int Console::i_removeMediumDriverFromVm(PCFGMNODE pCtlInst,
4471 const char *pcszDevice,
4472 unsigned uInstance,
4473 unsigned uLUN,
4474 StorageBus_T enmBus,
4475 bool fAttachDetach,
4476 bool fHotplug,
4477 bool fForceUnmount,
4478 PUVM pUVM,
4479 DeviceType_T enmDevType,
4480 PCFGMNODE *ppLunL0)
4481{
4482 int rc = VINF_SUCCESS;
4483 bool fAddLun = false;
4484
4485 /* First check if the LUN already exists. */
4486 PCFGMNODE pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
4487 AssertReturn(!VALID_PTR(pLunL0) || fAttachDetach, VERR_INTERNAL_ERROR);
4488
4489 if (pLunL0)
4490 {
4491 /*
4492 * Unmount the currently mounted medium if we don't just hot remove the
4493 * complete device (SATA) and it supports unmounting (DVD).
4494 */
4495 if ( (enmDevType != DeviceType_HardDisk)
4496 && !fHotplug)
4497 {
4498 rc = i_unmountMediumFromGuest(pUVM, enmBus, enmDevType, pcszDevice,
4499 uInstance, uLUN, fForceUnmount);
4500 if (RT_FAILURE(rc))
4501 return rc;
4502 }
4503
4504 /*
4505 * Don't detach the SCSI driver when unmounting the current medium
4506 * (we are not ripping out the device but only eject the medium).
4507 */
4508 char *pszDriverDetach = NULL;
4509 if ( !fHotplug
4510 && ( (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD)
4511 || enmBus == StorageBus_SAS
4512 || enmBus == StorageBus_SCSI
4513 || enmBus == StorageBus_VirtioSCSI
4514 || enmBus == StorageBus_USB))
4515 {
4516 /* Get the current attached driver we have to detach. */
4517 PCFGMNODE pDrvLun = CFGMR3GetChildF(pCtlInst, "LUN#%u/AttachedDriver/", uLUN);
4518 if (pDrvLun)
4519 {
4520 char szDriver[128];
4521 RT_ZERO(szDriver);
4522 rc = CFGMR3QueryString(pDrvLun, "Driver", &szDriver[0], sizeof(szDriver));
4523 if (RT_SUCCESS(rc))
4524 pszDriverDetach = RTStrDup(&szDriver[0]);
4525
4526 pLunL0 = pDrvLun;
4527 }
4528 }
4529
4530 if (enmBus == StorageBus_USB)
4531 rc = PDMR3UsbDriverDetach(pUVM, pcszDevice, uInstance, uLUN,
4532 pszDriverDetach, 0 /* iOccurence */,
4533 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
4534 else
4535 rc = PDMR3DriverDetach(pUVM, pcszDevice, uInstance, uLUN,
4536 pszDriverDetach, 0 /* iOccurence */,
4537 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
4538
4539 if (pszDriverDetach)
4540 {
4541 RTStrFree(pszDriverDetach);
4542 /* Remove the complete node and create new for the new config. */
4543 CFGMR3RemoveNode(pLunL0);
4544 pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
4545 if (pLunL0)
4546 {
4547 try
4548 {
4549 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4550 }
4551 catch (ConfigError &x)
4552 {
4553 // InsertConfig threw something:
4554 return x.m_vrc;
4555 }
4556 }
4557 }
4558 if (rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4559 rc = VINF_SUCCESS;
4560 AssertRCReturn(rc, rc);
4561
4562 /*
4563 * Don't remove the LUN except for IDE/floppy/NVMe (which connects directly to the medium driver
4564 * even for DVD devices) or if there is a hotplug event which rips out the complete device.
4565 */
4566 if ( fHotplug
4567 || enmBus == StorageBus_IDE
4568 || enmBus == StorageBus_Floppy
4569 || enmBus == StorageBus_PCIe
4570 || (enmBus == StorageBus_SATA && enmDevType != DeviceType_DVD))
4571 {
4572 fAddLun = true;
4573 CFGMR3RemoveNode(pLunL0);
4574 }
4575 }
4576 else
4577 fAddLun = true;
4578
4579 try
4580 {
4581 if (fAddLun)
4582 InsertConfigNode(pCtlInst, Utf8StrFmt("LUN#%u", uLUN).c_str(), &pLunL0);
4583 }
4584 catch (ConfigError &x)
4585 {
4586 // InsertConfig threw something:
4587 return x.m_vrc;
4588 }
4589
4590 if (ppLunL0)
4591 *ppLunL0 = pLunL0;
4592
4593 return rc;
4594}
4595
4596int Console::i_configMediumAttachment(const char *pcszDevice,
4597 unsigned uInstance,
4598 StorageBus_T enmBus,
4599 bool fUseHostIOCache,
4600 bool fBuiltinIOCache,
4601 bool fInsertDiskIntegrityDrv,
4602 bool fSetupMerge,
4603 unsigned uMergeSource,
4604 unsigned uMergeTarget,
4605 IMediumAttachment *pMediumAtt,
4606 MachineState_T aMachineState,
4607 HRESULT *phrc,
4608 bool fAttachDetach,
4609 bool fForceUnmount,
4610 bool fHotplug,
4611 PUVM pUVM,
4612 DeviceType_T *paLedDevType,
4613 PCFGMNODE *ppLunL0)
4614{
4615 // InsertConfig* throws
4616 try
4617 {
4618 int rc = VINF_SUCCESS;
4619 HRESULT hrc;
4620 Bstr bstr;
4621 PCFGMNODE pCtlInst = NULL;
4622
4623// #define RC_CHECK() AssertMsgReturn(RT_SUCCESS(rc), ("rc=%Rrc\n", rc), rc)
4624#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4625
4626 LONG lDev;
4627 hrc = pMediumAtt->COMGETTER(Device)(&lDev); H();
4628 LONG lPort;
4629 hrc = pMediumAtt->COMGETTER(Port)(&lPort); H();
4630 DeviceType_T lType;
4631 hrc = pMediumAtt->COMGETTER(Type)(&lType); H();
4632 BOOL fNonRotational;
4633 hrc = pMediumAtt->COMGETTER(NonRotational)(&fNonRotational); H();
4634 BOOL fDiscard;
4635 hrc = pMediumAtt->COMGETTER(Discard)(&fDiscard); H();
4636
4637 if (lType == DeviceType_DVD)
4638 fInsertDiskIntegrityDrv = false;
4639
4640 unsigned uLUN;
4641 PCFGMNODE pLunL0 = NULL;
4642 hrc = Console::i_storageBusPortDeviceToLun(enmBus, lPort, lDev, uLUN); H();
4643
4644 /* Determine the base path for the device instance. */
4645 if (enmBus != StorageBus_USB)
4646 pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "Devices/%s/%u/", pcszDevice, uInstance);
4647 else
4648 {
4649 /* If we hotplug a USB device create a new CFGM tree. */
4650 if (!fHotplug)
4651 pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "USB/%s/", pcszDevice);
4652 else
4653 pCtlInst = CFGMR3CreateTree(pUVM);
4654 }
4655 AssertReturn(pCtlInst, VERR_INTERNAL_ERROR);
4656
4657 if (enmBus == StorageBus_USB)
4658 {
4659 PCFGMNODE pCfg = NULL;
4660
4661 /* Create correct instance. */
4662 if (!fHotplug)
4663 {
4664 if (!fAttachDetach)
4665 InsertConfigNode(pCtlInst, Utf8StrFmt("%d", lPort).c_str(), &pCtlInst);
4666 else
4667 pCtlInst = CFGMR3GetChildF(pCtlInst, "%d/", lPort);
4668 }
4669
4670 if (!fAttachDetach)
4671 InsertConfigNode(pCtlInst, "Config", &pCfg);
4672
4673 uInstance = lPort; /* Overwrite uInstance with the correct one. */
4674
4675 if (!fHotplug && !fAttachDetach)
4676 {
4677 char aszUuid[RTUUID_STR_LENGTH + 1];
4678 USBStorageDevice UsbMsd = USBStorageDevice();
4679
4680 memset(aszUuid, 0, sizeof(aszUuid));
4681 rc = RTUuidCreate(&UsbMsd.mUuid);
4682 AssertRCReturn(rc, rc);
4683 rc = RTUuidToStr(&UsbMsd.mUuid, aszUuid, sizeof(aszUuid));
4684 AssertRCReturn(rc, rc);
4685
4686 UsbMsd.iPort = uInstance;
4687
4688 InsertConfigString(pCtlInst, "UUID", aszUuid);
4689 mUSBStorageDevices.push_back(UsbMsd);
4690
4691 /** @todo No LED after hotplugging. */
4692 /* Attach the status driver */
4693 i_attachStatusDriver(pCtlInst, DeviceType_HardDisk, 0, 7, &paLedDevType,
4694 &mapMediumAttachments, pcszDevice, 0);
4695 }
4696 }
4697
4698 rc = i_removeMediumDriverFromVm(pCtlInst, pcszDevice, uInstance, uLUN, enmBus, fAttachDetach,
4699 fHotplug, fForceUnmount, pUVM, lType, &pLunL0);
4700 if (RT_FAILURE(rc))
4701 return rc;
4702 if (ppLunL0)
4703 *ppLunL0 = pLunL0;
4704
4705 Utf8Str devicePath = Utf8StrFmt("%s/%u/LUN#%u", pcszDevice, uInstance, uLUN);
4706 mapMediumAttachments[devicePath] = pMediumAtt;
4707
4708 ComPtr<IMedium> ptrMedium;
4709 hrc = pMediumAtt->COMGETTER(Medium)(ptrMedium.asOutParam()); H();
4710
4711 /*
4712 * 1. Only check this for hard disk images.
4713 * 2. Only check during VM creation and not later, especially not during
4714 * taking an online snapshot!
4715 */
4716 if ( lType == DeviceType_HardDisk
4717 && ( aMachineState == MachineState_Starting
4718 || aMachineState == MachineState_Restoring))
4719 {
4720 rc = i_checkMediumLocation(ptrMedium, &fUseHostIOCache);
4721 if (RT_FAILURE(rc))
4722 return rc;
4723 }
4724
4725 BOOL fPassthrough = FALSE;
4726 if (ptrMedium.isNotNull())
4727 {
4728 BOOL fHostDrive;
4729 hrc = ptrMedium->COMGETTER(HostDrive)(&fHostDrive); H();
4730 if ( ( lType == DeviceType_DVD
4731 || lType == DeviceType_Floppy)
4732 && !fHostDrive)
4733 {
4734 /*
4735 * Informative logging.
4736 */
4737 Bstr strFile;
4738 hrc = ptrMedium->COMGETTER(Location)(strFile.asOutParam()); H();
4739 Utf8Str utfFile = Utf8Str(strFile);
4740 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
4741 (void)RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
4742 LogRel(("File system of '%s' (%s) is %s\n",
4743 utfFile.c_str(), lType == DeviceType_DVD ? "DVD" : "Floppy",
4744 RTFsTypeName(enmFsTypeFile)));
4745 }
4746
4747 if (fHostDrive)
4748 {
4749 hrc = pMediumAtt->COMGETTER(Passthrough)(&fPassthrough); H();
4750 }
4751 }
4752
4753 ComObjPtr<IBandwidthGroup> pBwGroup;
4754 Bstr strBwGroup;
4755 hrc = pMediumAtt->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
4756
4757 if (!pBwGroup.isNull())
4758 {
4759 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
4760 }
4761
4762 /*
4763 * Insert the SCSI driver for hotplug events on the SCSI/USB based storage controllers
4764 * or for SATA if the new device is a CD/DVD drive.
4765 */
4766 if ( (fHotplug || !fAttachDetach)
4767 && ( (enmBus == StorageBus_SCSI || enmBus == StorageBus_SAS || enmBus == StorageBus_USB || enmBus == StorageBus_VirtioSCSI)
4768 || (enmBus == StorageBus_SATA && lType == DeviceType_DVD && !fPassthrough)))
4769 {
4770 InsertConfigString(pLunL0, "Driver", "SCSI");
4771 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4772 }
4773
4774 rc = i_configMedium(pLunL0,
4775 !!fPassthrough,
4776 lType,
4777 fUseHostIOCache,
4778 fBuiltinIOCache,
4779 fInsertDiskIntegrityDrv,
4780 fSetupMerge,
4781 uMergeSource,
4782 uMergeTarget,
4783 strBwGroup.isEmpty() ? NULL : Utf8Str(strBwGroup).c_str(),
4784 !!fDiscard,
4785 !!fNonRotational,
4786 ptrMedium,
4787 aMachineState,
4788 phrc);
4789 if (RT_FAILURE(rc))
4790 return rc;
4791
4792 if (fAttachDetach)
4793 {
4794 /* Attach the new driver. */
4795 if (enmBus == StorageBus_USB)
4796 {
4797 if (fHotplug)
4798 {
4799 USBStorageDevice UsbMsd = USBStorageDevice();
4800 RTUuidCreate(&UsbMsd.mUuid);
4801 UsbMsd.iPort = uInstance;
4802 rc = PDMR3UsbCreateEmulatedDevice(pUVM, pcszDevice, pCtlInst, &UsbMsd.mUuid, NULL);
4803 if (RT_SUCCESS(rc))
4804 mUSBStorageDevices.push_back(UsbMsd);
4805 }
4806 else
4807 rc = PDMR3UsbDriverAttach(pUVM, pcszDevice, uInstance, uLUN,
4808 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4809 }
4810 else if ( !fHotplug
4811 && ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI || enmBus == StorageBus_VirtioSCSI)
4812 || (enmBus == StorageBus_SATA && lType == DeviceType_DVD)))
4813 rc = PDMR3DriverAttach(pUVM, pcszDevice, uInstance, uLUN,
4814 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4815 else
4816 rc = PDMR3DeviceAttach(pUVM, pcszDevice, uInstance, uLUN,
4817 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4818 AssertRCReturn(rc, rc);
4819
4820 /*
4821 * Make the secret key helper interface known to the VD driver if it is attached,
4822 * so we can get notified about missing keys.
4823 */
4824 PPDMIBASE pIBase = NULL;
4825 rc = PDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "VD", &pIBase);
4826 if (RT_SUCCESS(rc) && pIBase)
4827 {
4828 PPDMIMEDIA pIMedium = (PPDMIMEDIA)pIBase->pfnQueryInterface(pIBase, PDMIMEDIA_IID);
4829 if (pIMedium)
4830 {
4831 rc = pIMedium->pfnSetSecKeyIf(pIMedium, mpIfSecKey, mpIfSecKeyHlp);
4832 Assert(RT_SUCCESS(rc) || rc == VERR_NOT_SUPPORTED);
4833 }
4834 }
4835
4836 /* There is no need to handle removable medium mounting, as we
4837 * unconditionally replace everthing including the block driver level.
4838 * This means the new medium will be picked up automatically. */
4839 }
4840
4841 if (paLedDevType)
4842 paLedDevType[uLUN] = lType;
4843
4844 /* Dump the changed LUN if possible, dump the complete device otherwise */
4845 if ( aMachineState != MachineState_Starting
4846 && aMachineState != MachineState_Restoring)
4847 CFGMR3Dump(pLunL0 ? pLunL0 : pCtlInst);
4848 }
4849 catch (ConfigError &x)
4850 {
4851 // InsertConfig threw something:
4852 return x.m_vrc;
4853 }
4854
4855#undef H
4856
4857 return VINF_SUCCESS;
4858}
4859
4860int Console::i_configMedium(PCFGMNODE pLunL0,
4861 bool fPassthrough,
4862 DeviceType_T enmType,
4863 bool fUseHostIOCache,
4864 bool fBuiltinIOCache,
4865 bool fInsertDiskIntegrityDrv,
4866 bool fSetupMerge,
4867 unsigned uMergeSource,
4868 unsigned uMergeTarget,
4869 const char *pcszBwGroup,
4870 bool fDiscard,
4871 bool fNonRotational,
4872 ComPtr<IMedium> ptrMedium,
4873 MachineState_T aMachineState,
4874 HRESULT *phrc)
4875{
4876 // InsertConfig* throws
4877 try
4878 {
4879 HRESULT hrc;
4880 Bstr bstr;
4881 PCFGMNODE pCfg = NULL;
4882
4883#define H() \
4884 AssertMsgReturnStmt(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), if (phrc) *phrc = hrc, Global::vboxStatusCodeFromCOM(hrc))
4885
4886
4887 BOOL fHostDrive = FALSE;
4888 MediumType_T mediumType = MediumType_Normal;
4889 if (ptrMedium.isNotNull())
4890 {
4891 hrc = ptrMedium->COMGETTER(HostDrive)(&fHostDrive); H();
4892 hrc = ptrMedium->COMGETTER(Type)(&mediumType); H();
4893 }
4894
4895 if (fHostDrive)
4896 {
4897 Assert(ptrMedium.isNotNull());
4898 if (enmType == DeviceType_DVD)
4899 {
4900 InsertConfigString(pLunL0, "Driver", "HostDVD");
4901 InsertConfigNode(pLunL0, "Config", &pCfg);
4902
4903 hrc = ptrMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4904 InsertConfigString(pCfg, "Path", bstr);
4905
4906 InsertConfigInteger(pCfg, "Passthrough", fPassthrough);
4907 }
4908 else if (enmType == DeviceType_Floppy)
4909 {
4910 InsertConfigString(pLunL0, "Driver", "HostFloppy");
4911 InsertConfigNode(pLunL0, "Config", &pCfg);
4912
4913 hrc = ptrMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4914 InsertConfigString(pCfg, "Path", bstr);
4915 }
4916 }
4917 else
4918 {
4919 if (fInsertDiskIntegrityDrv)
4920 {
4921 /*
4922 * The actual configuration is done through CFGM extra data
4923 * for each inserted driver separately.
4924 */
4925 InsertConfigString(pLunL0, "Driver", "DiskIntegrity");
4926 InsertConfigNode(pLunL0, "Config", &pCfg);
4927 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4928 }
4929
4930 InsertConfigString(pLunL0, "Driver", "VD");
4931 InsertConfigNode(pLunL0, "Config", &pCfg);
4932 switch (enmType)
4933 {
4934 case DeviceType_DVD:
4935 InsertConfigString(pCfg, "Type", "DVD");
4936 InsertConfigInteger(pCfg, "Mountable", 1);
4937 break;
4938 case DeviceType_Floppy:
4939 InsertConfigString(pCfg, "Type", "Floppy 1.44");
4940 InsertConfigInteger(pCfg, "Mountable", 1);
4941 break;
4942 case DeviceType_HardDisk:
4943 default:
4944 InsertConfigString(pCfg, "Type", "HardDisk");
4945 InsertConfigInteger(pCfg, "Mountable", 0);
4946 }
4947
4948 if ( ptrMedium.isNotNull()
4949 && ( enmType == DeviceType_DVD
4950 || enmType == DeviceType_Floppy)
4951 )
4952 {
4953 // if this medium represents an ISO image and this image is inaccessible,
4954 // the ignore it instead of causing a failure; this can happen when we
4955 // restore a VM state and the ISO has disappeared, e.g. because the Guest
4956 // Additions were mounted and the user upgraded VirtualBox. Previously
4957 // we failed on startup, but that's not good because the only way out then
4958 // would be to discard the VM state...
4959 MediumState_T mediumState;
4960 hrc = ptrMedium->RefreshState(&mediumState); H();
4961 if (mediumState == MediumState_Inaccessible)
4962 {
4963 Bstr loc;
4964 hrc = ptrMedium->COMGETTER(Location)(loc.asOutParam()); H();
4965 i_atVMRuntimeErrorCallbackF(0, "DvdOrFloppyImageInaccessible",
4966 "The image file '%ls' is inaccessible and is being ignored. "
4967 "Please select a different image file for the virtual %s drive.",
4968 loc.raw(),
4969 enmType == DeviceType_DVD ? "DVD" : "floppy");
4970 ptrMedium.setNull();
4971 }
4972 }
4973
4974 if (ptrMedium.isNotNull())
4975 {
4976 /* Start with length of parent chain, as the list is reversed */
4977 unsigned uImage = 0;
4978 ComPtr<IMedium> ptrTmp = ptrMedium;
4979 while (ptrTmp.isNotNull())
4980 {
4981 uImage++;
4982 ComPtr<IMedium> ptrParent;
4983 hrc = ptrTmp->COMGETTER(Parent)(ptrParent.asOutParam()); H();
4984 ptrTmp = ptrParent;
4985 }
4986 /* Index of last image */
4987 uImage--;
4988
4989# ifdef VBOX_WITH_EXTPACK
4990 if (mptrExtPackManager->i_isExtPackUsable(ORACLE_PUEL_EXTPACK_NAME))
4991 {
4992 /* Configure loading the VDPlugin. */
4993 static const char s_szVDPlugin[] = "VDPluginCrypt";
4994 PCFGMNODE pCfgPlugins = NULL;
4995 PCFGMNODE pCfgPlugin = NULL;
4996 Utf8Str strPlugin;
4997 hrc = mptrExtPackManager->i_getLibraryPathForExtPack(s_szVDPlugin, ORACLE_PUEL_EXTPACK_NAME, &strPlugin);
4998 // Don't fail, this is optional!
4999 if (SUCCEEDED(hrc))
5000 {
5001 InsertConfigNode(pCfg, "Plugins", &pCfgPlugins);
5002 InsertConfigNode(pCfgPlugins, s_szVDPlugin, &pCfgPlugin);
5003 InsertConfigString(pCfgPlugin, "Path", strPlugin.c_str());
5004 }
5005 }
5006# endif
5007
5008 hrc = ptrMedium->COMGETTER(Location)(bstr.asOutParam()); H();
5009 InsertConfigString(pCfg, "Path", bstr);
5010
5011 hrc = ptrMedium->COMGETTER(Format)(bstr.asOutParam()); H();
5012 InsertConfigString(pCfg, "Format", bstr);
5013
5014 if (mediumType == MediumType_Readonly)
5015 InsertConfigInteger(pCfg, "ReadOnly", 1);
5016 else if (enmType == DeviceType_Floppy)
5017 InsertConfigInteger(pCfg, "MaybeReadOnly", 1);
5018
5019 /* Start without exclusive write access to the images. */
5020 /** @todo Live Migration: I don't quite like this, we risk screwing up when
5021 * we're resuming the VM if some 3rd dude have any of the VDIs open
5022 * with write sharing denied. However, if the two VMs are sharing a
5023 * image it really is necessary....
5024 *
5025 * So, on the "lock-media" command, the target teleporter should also
5026 * make DrvVD undo TempReadOnly. It gets interesting if we fail after
5027 * that. Grumble. */
5028 if ( enmType == DeviceType_HardDisk
5029 && aMachineState == MachineState_TeleportingIn)
5030 InsertConfigInteger(pCfg, "TempReadOnly", 1);
5031
5032 /* Flag for opening the medium for sharing between VMs. This
5033 * is done at the moment only for the first (and only) medium
5034 * in the chain, as shared media can have no diffs. */
5035 if (mediumType == MediumType_Shareable)
5036 InsertConfigInteger(pCfg, "Shareable", 1);
5037
5038 if (!fUseHostIOCache)
5039 {
5040 InsertConfigInteger(pCfg, "UseNewIo", 1);
5041 /*
5042 * Activate the builtin I/O cache for harddisks only.
5043 * It caches writes only which doesn't make sense for DVD drives
5044 * and just increases the overhead.
5045 */
5046 if ( fBuiltinIOCache
5047 && (enmType == DeviceType_HardDisk))
5048 InsertConfigInteger(pCfg, "BlockCache", 1);
5049 }
5050
5051 if (fSetupMerge)
5052 {
5053 InsertConfigInteger(pCfg, "SetupMerge", 1);
5054 if (uImage == uMergeSource)
5055 InsertConfigInteger(pCfg, "MergeSource", 1);
5056 else if (uImage == uMergeTarget)
5057 InsertConfigInteger(pCfg, "MergeTarget", 1);
5058 }
5059
5060 if (pcszBwGroup)
5061 InsertConfigString(pCfg, "BwGroup", pcszBwGroup);
5062
5063 if (fDiscard)
5064 InsertConfigInteger(pCfg, "Discard", 1);
5065
5066 if (fNonRotational)
5067 InsertConfigInteger(pCfg, "NonRotationalMedium", 1);
5068
5069 /* Pass all custom parameters. */
5070 bool fHostIP = true;
5071 bool fEncrypted = false;
5072 hrc = i_configMediumProperties(pCfg, ptrMedium, &fHostIP, &fEncrypted); H();
5073
5074 /* Create an inverted list of parents. */
5075 uImage--;
5076 ComPtr<IMedium> ptrParentMedium = ptrMedium;
5077 for (PCFGMNODE pParent = pCfg;; uImage--)
5078 {
5079 ComPtr<IMedium> ptrCurMedium;
5080 hrc = ptrParentMedium->COMGETTER(Parent)(ptrCurMedium.asOutParam()); H();
5081 if (ptrCurMedium.isNull())
5082 break;
5083
5084 PCFGMNODE pCur;
5085 InsertConfigNode(pParent, "Parent", &pCur);
5086 hrc = ptrCurMedium->COMGETTER(Location)(bstr.asOutParam()); H();
5087 InsertConfigString(pCur, "Path", bstr);
5088
5089 hrc = ptrCurMedium->COMGETTER(Format)(bstr.asOutParam()); H();
5090 InsertConfigString(pCur, "Format", bstr);
5091
5092 if (fSetupMerge)
5093 {
5094 if (uImage == uMergeSource)
5095 InsertConfigInteger(pCur, "MergeSource", 1);
5096 else if (uImage == uMergeTarget)
5097 InsertConfigInteger(pCur, "MergeTarget", 1);
5098 }
5099
5100 /* Configure medium properties. */
5101 hrc = i_configMediumProperties(pCur, ptrCurMedium, &fHostIP, &fEncrypted); H();
5102
5103 /* next */
5104 pParent = pCur;
5105 ptrParentMedium = ptrCurMedium;
5106 }
5107
5108 /* Custom code: put marker to not use host IP stack to driver
5109 * configuration node. Simplifies life of DrvVD a bit. */
5110 if (!fHostIP)
5111 InsertConfigInteger(pCfg, "HostIPStack", 0);
5112
5113 if (fEncrypted)
5114 m_cDisksEncrypted++;
5115 }
5116 else
5117 {
5118 /* Set empty drive flag for DVD or floppy without media. */
5119 if ( enmType == DeviceType_DVD
5120 || enmType == DeviceType_Floppy)
5121 InsertConfigInteger(pCfg, "EmptyDrive", 1);
5122 }
5123 }
5124#undef H
5125 }
5126 catch (ConfigError &x)
5127 {
5128 // InsertConfig threw something:
5129 return x.m_vrc;
5130 }
5131
5132 return VINF_SUCCESS;
5133}
5134
5135/**
5136 * Adds the medium properties to the CFGM tree.
5137 *
5138 * @returns VBox status code.
5139 * @param pCur The current CFGM node.
5140 * @param pMedium The medium object to configure.
5141 * @param pfHostIP Where to return the value of the \"HostIPStack\" property if found.
5142 * @param pfEncrypted Where to return whether the medium is encrypted.
5143 */
5144int Console::i_configMediumProperties(PCFGMNODE pCur, IMedium *pMedium, bool *pfHostIP, bool *pfEncrypted)
5145{
5146 /* Pass all custom parameters. */
5147 SafeArray<BSTR> aNames;
5148 SafeArray<BSTR> aValues;
5149 HRESULT hrc = pMedium->GetProperties(NULL, ComSafeArrayAsOutParam(aNames),
5150 ComSafeArrayAsOutParam(aValues));
5151
5152 if ( SUCCEEDED(hrc)
5153 && aNames.size() != 0)
5154 {
5155 PCFGMNODE pVDC;
5156 InsertConfigNode(pCur, "VDConfig", &pVDC);
5157 for (size_t ii = 0; ii < aNames.size(); ++ii)
5158 {
5159 if (aValues[ii] && *aValues[ii])
5160 {
5161 Utf8Str name = aNames[ii];
5162 Utf8Str value = aValues[ii];
5163 size_t offSlash = name.find("/", 0);
5164 if ( offSlash != name.npos
5165 && !name.startsWith("Special/"))
5166 {
5167 com::Utf8Str strFilter;
5168 com::Utf8Str strKey;
5169
5170 hrc = strFilter.assignEx(name, 0, offSlash);
5171 if (FAILED(hrc))
5172 break;
5173
5174 hrc = strKey.assignEx(name, offSlash + 1, name.length() - offSlash - 1); /* Skip slash */
5175 if (FAILED(hrc))
5176 break;
5177
5178 PCFGMNODE pCfgFilterConfig = CFGMR3GetChild(pVDC, strFilter.c_str());
5179 if (!pCfgFilterConfig)
5180 InsertConfigNode(pVDC, strFilter.c_str(), &pCfgFilterConfig);
5181
5182 InsertConfigString(pCfgFilterConfig, strKey.c_str(), value);
5183 }
5184 else
5185 {
5186 InsertConfigString(pVDC, name.c_str(), value);
5187 if ( name.compare("HostIPStack") == 0
5188 && value.compare("0") == 0)
5189 *pfHostIP = false;
5190 }
5191
5192 if ( name.compare("CRYPT/KeyId") == 0
5193 && pfEncrypted)
5194 *pfEncrypted = true;
5195 }
5196 }
5197 }
5198
5199 return hrc;
5200}
5201
5202
5203/**
5204 * Construct the Network configuration tree
5205 *
5206 * @returns VBox status code.
5207 *
5208 * @param pszDevice The PDM device name.
5209 * @param uInstance The PDM device instance.
5210 * @param uLun The PDM LUN number of the drive.
5211 * @param aNetworkAdapter The network adapter whose attachment needs to be changed
5212 * @param pCfg Configuration node for the device
5213 * @param pLunL0 To store the pointer to the LUN#0.
5214 * @param pInst The instance CFGM node
5215 * @param fAttachDetach To determine if the network attachment should
5216 * be attached/detached after/before
5217 * configuration.
5218 * @param fIgnoreConnectFailure
5219 * True if connection failures should be ignored
5220 * (makes only sense for bridged/host-only networks).
5221 *
5222 * @note Locks this object for writing.
5223 * @thread EMT
5224 */
5225int Console::i_configNetwork(const char *pszDevice,
5226 unsigned uInstance,
5227 unsigned uLun,
5228 INetworkAdapter *aNetworkAdapter,
5229 PCFGMNODE pCfg,
5230 PCFGMNODE pLunL0,
5231 PCFGMNODE pInst,
5232 bool fAttachDetach,
5233 bool fIgnoreConnectFailure)
5234{
5235 RT_NOREF(fIgnoreConnectFailure);
5236 AutoCaller autoCaller(this);
5237 AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED);
5238
5239 // InsertConfig* throws
5240 try
5241 {
5242 int rc = VINF_SUCCESS;
5243 HRESULT hrc;
5244 Bstr bstr;
5245
5246#ifdef VBOX_WITH_CLOUD_NET
5247 /* We'll need device's pCfg for cloud attachments */
5248 PCFGMNODE pDevCfg = pCfg;
5249#endif /* VBOX_WITH_CLOUD_NET */
5250
5251#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
5252
5253 /*
5254 * Locking the object before doing VMR3* calls is quite safe here, since
5255 * we're on EMT. Write lock is necessary because we indirectly modify the
5256 * meAttachmentType member.
5257 */
5258 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
5259
5260 ComPtr<IMachine> pMachine = i_machine();
5261
5262 ComPtr<IVirtualBox> virtualBox;
5263 hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam()); H();
5264
5265 ComPtr<IHost> host;
5266 hrc = virtualBox->COMGETTER(Host)(host.asOutParam()); H();
5267
5268 BOOL fSniffer;
5269 hrc = aNetworkAdapter->COMGETTER(TraceEnabled)(&fSniffer); H();
5270
5271 NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy;
5272 hrc = aNetworkAdapter->COMGETTER(PromiscModePolicy)(&enmPromiscModePolicy); H();
5273 const char *pszPromiscuousGuestPolicy;
5274 switch (enmPromiscModePolicy)
5275 {
5276 case NetworkAdapterPromiscModePolicy_Deny: pszPromiscuousGuestPolicy = "deny"; break;
5277 case NetworkAdapterPromiscModePolicy_AllowNetwork: pszPromiscuousGuestPolicy = "allow-network"; break;
5278 case NetworkAdapterPromiscModePolicy_AllowAll: pszPromiscuousGuestPolicy = "allow-all"; break;
5279 default: AssertFailedReturn(VERR_INTERNAL_ERROR_4);
5280 }
5281
5282 if (fAttachDetach)
5283 {
5284 rc = PDMR3DeviceDetach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/);
5285 if (rc == VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN)
5286 rc = VINF_SUCCESS;
5287 AssertLogRelRCReturn(rc, rc);
5288
5289 /* Nuke anything which might have been left behind. */
5290 CFGMR3RemoveNode(CFGMR3GetChildF(pInst, "LUN#%u", uLun));
5291 }
5292
5293 Bstr networkName, trunkName, trunkType;
5294 NetworkAttachmentType_T eAttachmentType;
5295 hrc = aNetworkAdapter->COMGETTER(AttachmentType)(&eAttachmentType); H();
5296
5297#ifdef VBOX_WITH_NETSHAPER
5298 ComObjPtr<IBandwidthGroup> pBwGroup;
5299 Bstr strBwGroup;
5300 hrc = aNetworkAdapter->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
5301
5302 if (!pBwGroup.isNull())
5303 {
5304 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
5305 }
5306#endif /* VBOX_WITH_NETSHAPER */
5307
5308 AssertMsg(uLun == 0, ("Network attachments with LUN > 0 are not supported yet\n"));
5309 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", uLun);
5310
5311 /*
5312 * Do not insert neither a shaper nor a sniffer if we are not attached to anything.
5313 * This way we can easily detect if we are attached to anything at the device level.
5314 */
5315#ifdef VBOX_WITH_NETSHAPER
5316 if (!strBwGroup.isEmpty() && eAttachmentType != NetworkAttachmentType_Null)
5317 {
5318 InsertConfigString(pLunL0, "Driver", "NetShaper");
5319 InsertConfigNode(pLunL0, "Config", &pCfg);
5320 InsertConfigString(pCfg, "BwGroup", strBwGroup);
5321 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
5322 }
5323#endif /* VBOX_WITH_NETSHAPER */
5324
5325 if (fSniffer && eAttachmentType != NetworkAttachmentType_Null)
5326 {
5327 InsertConfigString(pLunL0, "Driver", "NetSniffer");
5328 InsertConfigNode(pLunL0, "Config", &pCfg);
5329 hrc = aNetworkAdapter->COMGETTER(TraceFile)(bstr.asOutParam()); H();
5330 if (!bstr.isEmpty()) /* check convention for indicating default file. */
5331 InsertConfigString(pCfg, "File", bstr);
5332 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
5333 }
5334
5335 switch (eAttachmentType)
5336 {
5337 case NetworkAttachmentType_Null:
5338 break;
5339
5340 case NetworkAttachmentType_NAT:
5341 {
5342 ComPtr<INATEngine> natEngine;
5343 hrc = aNetworkAdapter->COMGETTER(NATEngine)(natEngine.asOutParam()); H();
5344 InsertConfigString(pLunL0, "Driver", "NAT");
5345 InsertConfigNode(pLunL0, "Config", &pCfg);
5346
5347 /* Configure TFTP prefix and boot filename. */
5348 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
5349 if (!bstr.isEmpty())
5350 InsertConfigString(pCfg, "TFTPPrefix", Utf8StrFmt("%ls%c%s", bstr.raw(), RTPATH_DELIMITER, "TFTP"));
5351 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
5352 InsertConfigString(pCfg, "BootFile", Utf8StrFmt("%ls.pxe", bstr.raw()));
5353
5354 hrc = natEngine->COMGETTER(Network)(bstr.asOutParam()); H();
5355 if (!bstr.isEmpty())
5356 InsertConfigString(pCfg, "Network", bstr);
5357 else
5358 {
5359 ULONG uSlot;
5360 hrc = aNetworkAdapter->COMGETTER(Slot)(&uSlot); H();
5361 InsertConfigString(pCfg, "Network", Utf8StrFmt("10.0.%d.0/24", uSlot+2));
5362 }
5363 hrc = natEngine->COMGETTER(HostIP)(bstr.asOutParam()); H();
5364 if (!bstr.isEmpty())
5365 InsertConfigString(pCfg, "BindIP", bstr);
5366 ULONG mtu = 0;
5367 ULONG sockSnd = 0;
5368 ULONG sockRcv = 0;
5369 ULONG tcpSnd = 0;
5370 ULONG tcpRcv = 0;
5371 hrc = natEngine->GetNetworkSettings(&mtu, &sockSnd, &sockRcv, &tcpSnd, &tcpRcv); H();
5372 if (mtu)
5373 InsertConfigInteger(pCfg, "SlirpMTU", mtu);
5374 if (sockRcv)
5375 InsertConfigInteger(pCfg, "SockRcv", sockRcv);
5376 if (sockSnd)
5377 InsertConfigInteger(pCfg, "SockSnd", sockSnd);
5378 if (tcpRcv)
5379 InsertConfigInteger(pCfg, "TcpRcv", tcpRcv);
5380 if (tcpSnd)
5381 InsertConfigInteger(pCfg, "TcpSnd", tcpSnd);
5382 hrc = natEngine->COMGETTER(TFTPPrefix)(bstr.asOutParam()); H();
5383 if (!bstr.isEmpty())
5384 {
5385 RemoveConfigValue(pCfg, "TFTPPrefix");
5386 InsertConfigString(pCfg, "TFTPPrefix", bstr);
5387 }
5388 hrc = natEngine->COMGETTER(TFTPBootFile)(bstr.asOutParam()); H();
5389 if (!bstr.isEmpty())
5390 {
5391 RemoveConfigValue(pCfg, "BootFile");
5392 InsertConfigString(pCfg, "BootFile", bstr);
5393 }
5394 hrc = natEngine->COMGETTER(TFTPNextServer)(bstr.asOutParam()); H();
5395 if (!bstr.isEmpty())
5396 InsertConfigString(pCfg, "NextServer", bstr);
5397 BOOL fDNSFlag;
5398 hrc = natEngine->COMGETTER(DNSPassDomain)(&fDNSFlag); H();
5399 InsertConfigInteger(pCfg, "PassDomain", fDNSFlag);
5400 hrc = natEngine->COMGETTER(DNSProxy)(&fDNSFlag); H();
5401 InsertConfigInteger(pCfg, "DNSProxy", fDNSFlag);
5402 hrc = natEngine->COMGETTER(DNSUseHostResolver)(&fDNSFlag); H();
5403 InsertConfigInteger(pCfg, "UseHostResolver", fDNSFlag);
5404
5405 ULONG aliasMode;
5406 hrc = natEngine->COMGETTER(AliasMode)(&aliasMode); H();
5407 InsertConfigInteger(pCfg, "AliasMode", aliasMode);
5408
5409 /* port-forwarding */
5410 SafeArray<BSTR> pfs;
5411 hrc = natEngine->COMGETTER(Redirects)(ComSafeArrayAsOutParam(pfs)); H();
5412
5413 PCFGMNODE pPFTree = NULL;
5414 if (pfs.size() > 0)
5415 InsertConfigNode(pCfg, "PortForwarding", &pPFTree);
5416
5417 for (unsigned int i = 0; i < pfs.size(); ++i)
5418 {
5419 PCFGMNODE pPF = NULL; /* /Devices/Dev/.../Config/PortForwarding/$n/ */
5420
5421 uint16_t port = 0;
5422 Utf8Str utf = pfs[i];
5423 Utf8Str strName;
5424 Utf8Str strProto;
5425 Utf8Str strHostPort;
5426 Utf8Str strHostIP;
5427 Utf8Str strGuestPort;
5428 Utf8Str strGuestIP;
5429 size_t pos, ppos;
5430 pos = ppos = 0;
5431#define ITERATE_TO_NEXT_TERM(res, str, pos, ppos) \
5432 { \
5433 pos = str.find(",", ppos); \
5434 if (pos == Utf8Str::npos) \
5435 { \
5436 Log(( #res " extracting from %s is failed\n", str.c_str())); \
5437 continue; \
5438 } \
5439 res = str.substr(ppos, pos - ppos); \
5440 Log2((#res " %s pos:%d, ppos:%d\n", res.c_str(), pos, ppos)); \
5441 ppos = pos + 1; \
5442 } /* no do { ... } while because of 'continue' */
5443 ITERATE_TO_NEXT_TERM(strName, utf, pos, ppos);
5444 ITERATE_TO_NEXT_TERM(strProto, utf, pos, ppos);
5445 ITERATE_TO_NEXT_TERM(strHostIP, utf, pos, ppos);
5446 ITERATE_TO_NEXT_TERM(strHostPort, utf, pos, ppos);
5447 ITERATE_TO_NEXT_TERM(strGuestIP, utf, pos, ppos);
5448 strGuestPort = utf.substr(ppos, utf.length() - ppos);
5449#undef ITERATE_TO_NEXT_TERM
5450
5451 uint32_t proto = strProto.toUInt32();
5452 bool fValid = true;
5453 switch (proto)
5454 {
5455 case NATProtocol_UDP:
5456 strProto = "UDP";
5457 break;
5458 case NATProtocol_TCP:
5459 strProto = "TCP";
5460 break;
5461 default:
5462 fValid = false;
5463 }
5464 /* continue with next rule if no valid proto was passed */
5465 if (!fValid)
5466 continue;
5467
5468 InsertConfigNode(pPFTree, Utf8StrFmt("%u", i).c_str(), &pPF);
5469
5470 if (!strName.isEmpty())
5471 InsertConfigString(pPF, "Name", strName);
5472
5473 InsertConfigString(pPF, "Protocol", strProto);
5474
5475 if (!strHostIP.isEmpty())
5476 InsertConfigString(pPF, "BindIP", strHostIP);
5477
5478 if (!strGuestIP.isEmpty())
5479 InsertConfigString(pPF, "GuestIP", strGuestIP);
5480
5481 port = RTStrToUInt16(strHostPort.c_str());
5482 if (port)
5483 InsertConfigInteger(pPF, "HostPort", port);
5484
5485 port = RTStrToUInt16(strGuestPort.c_str());
5486 if (port)
5487 InsertConfigInteger(pPF, "GuestPort", port);
5488 }
5489 break;
5490 }
5491
5492 case NetworkAttachmentType_Bridged:
5493 {
5494#if (defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)) && !defined(VBOX_WITH_NETFLT)
5495 hrc = i_attachToTapInterface(aNetworkAdapter);
5496 if (FAILED(hrc))
5497 {
5498 switch (hrc)
5499 {
5500 case VERR_ACCESS_DENIED:
5501 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5502 "Failed to open '/dev/net/tun' for read/write access. Please check the "
5503 "permissions of that node. Either run 'chmod 0666 /dev/net/tun' or "
5504 "change the group of that node and make yourself a member of that group. Make "
5505 "sure that these changes are permanent, especially if you are "
5506 "using udev"));
5507 default:
5508 AssertMsgFailed(("Could not attach to host interface! Bad!\n"));
5509 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5510 "Failed to initialize Host Interface Networking"));
5511 }
5512 }
5513
5514 Assert((intptr_t)maTapFD[uInstance] >= 0);
5515 if ((intptr_t)maTapFD[uInstance] >= 0)
5516 {
5517 InsertConfigString(pLunL0, "Driver", "HostInterface");
5518 InsertConfigNode(pLunL0, "Config", &pCfg);
5519 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
5520 }
5521
5522#elif defined(VBOX_WITH_NETFLT)
5523 /*
5524 * This is the new VBoxNetFlt+IntNet stuff.
5525 */
5526 Bstr BridgedIfName;
5527 hrc = aNetworkAdapter->COMGETTER(BridgedInterface)(BridgedIfName.asOutParam());
5528 if (FAILED(hrc))
5529 {
5530 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(BridgedInterface) failed, hrc (0x%x)\n", hrc));
5531 H();
5532 }
5533
5534 Utf8Str BridgedIfNameUtf8(BridgedIfName);
5535 const char *pszBridgedIfName = BridgedIfNameUtf8.c_str();
5536
5537 ComPtr<IHostNetworkInterface> hostInterface;
5538 hrc = host->FindHostNetworkInterfaceByName(BridgedIfName.raw(),
5539 hostInterface.asOutParam());
5540 if (!SUCCEEDED(hrc))
5541 {
5542 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: FindByName failed, rc=%Rhrc (0x%x)\n", hrc, hrc));
5543 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5544 N_("Nonexistent host networking interface, name '%ls'"),
5545 BridgedIfName.raw());
5546 }
5547
5548# if defined(RT_OS_DARWIN)
5549 /* The name is on the form 'ifX: long name', chop it off at the colon. */
5550 char szTrunk[INTNET_MAX_TRUNK_NAME];
5551 RTStrCopy(szTrunk, sizeof(szTrunk), pszBridgedIfName);
5552 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
5553// Quick fix for @bugref{5633}
5554// if (!pszColon)
5555// {
5556// /*
5557// * Dynamic changing of attachment causes an attempt to configure
5558// * network with invalid host adapter (as it is must be changed before
5559// * the attachment), calling Detach here will cause a deadlock.
5560// * See @bugref{4750}.
5561// * hrc = aNetworkAdapter->Detach(); H();
5562// */
5563// return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5564// N_("Malformed host interface networking name '%ls'"),
5565// BridgedIfName.raw());
5566// }
5567 if (pszColon)
5568 *pszColon = '\0';
5569 const char *pszTrunk = szTrunk;
5570
5571# elif defined(RT_OS_SOLARIS)
5572 /* The name is on the form format 'ifX[:1] - long name, chop it off at space. */
5573 char szTrunk[256];
5574 strlcpy(szTrunk, pszBridgedIfName, sizeof(szTrunk));
5575 char *pszSpace = (char *)memchr(szTrunk, ' ', sizeof(szTrunk));
5576
5577 /*
5578 * Currently don't bother about malformed names here for the sake of people using
5579 * VBoxManage and setting only the NIC name from there. If there is a space we
5580 * chop it off and proceed, otherwise just use whatever we've got.
5581 */
5582 if (pszSpace)
5583 *pszSpace = '\0';
5584
5585 /* Chop it off at the colon (zone naming eg: e1000g:1 we need only the e1000g) */
5586 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
5587 if (pszColon)
5588 *pszColon = '\0';
5589
5590 const char *pszTrunk = szTrunk;
5591
5592# elif defined(RT_OS_WINDOWS)
5593 HostNetworkInterfaceType_T eIfType;
5594 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
5595 if (FAILED(hrc))
5596 {
5597 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
5598 H();
5599 }
5600
5601 if (eIfType != HostNetworkInterfaceType_Bridged)
5602 {
5603 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5604 N_("Interface ('%ls') is not a Bridged Adapter interface"),
5605 BridgedIfName.raw());
5606 }
5607
5608 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
5609 if (FAILED(hrc))
5610 {
5611 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
5612 H();
5613 }
5614 Guid hostIFGuid(bstr);
5615
5616 INetCfg *pNc;
5617 ComPtr<INetCfgComponent> pAdaptorComponent;
5618 LPWSTR pszApp;
5619
5620 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
5621 Assert(hrc == S_OK);
5622 if (hrc != S_OK)
5623 {
5624 LogRel(("NetworkAttachmentType_Bridged: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5625 H();
5626 }
5627
5628 /* get the adapter's INetCfgComponent*/
5629 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
5630 pAdaptorComponent.asOutParam());
5631 if (hrc != S_OK)
5632 {
5633 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5634 LogRel(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)\n", hrc));
5635 H();
5636 }
5637# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
5638 char szTrunkName[INTNET_MAX_TRUNK_NAME];
5639 char *pszTrunkName = szTrunkName;
5640 wchar_t * pswzBindName;
5641 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
5642 Assert(hrc == S_OK);
5643 if (hrc == S_OK)
5644 {
5645 int cwBindName = (int)wcslen(pswzBindName) + 1;
5646 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
5647 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
5648 {
5649 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
5650 pszTrunkName += cbFullBindNamePrefix-1;
5651 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
5652 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
5653 {
5654 DWORD err = GetLastError();
5655 hrc = HRESULT_FROM_WIN32(err);
5656 AssertMsgFailed(("hrc=%Rhrc %#x\n", hrc, hrc));
5657 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
5658 hrc, hrc, err));
5659 }
5660 }
5661 else
5662 {
5663 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: insufficient szTrunkName buffer space\n"));
5664 /** @todo set appropriate error code */
5665 hrc = E_FAIL;
5666 }
5667
5668 if (hrc != S_OK)
5669 {
5670 AssertFailed();
5671 CoTaskMemFree(pswzBindName);
5672 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5673 H();
5674 }
5675
5676 /* we're not freeing the bind name since we'll use it later for detecting wireless*/
5677 }
5678 else
5679 {
5680 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5681 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)",
5682 hrc));
5683 H();
5684 }
5685
5686 const char *pszTrunk = szTrunkName;
5687 /* we're not releasing the INetCfg stuff here since we use it later to figure out whether it is wireless */
5688
5689# elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
5690# if defined(RT_OS_FREEBSD)
5691 /*
5692 * If we bridge to a tap interface open it the `old' direct way.
5693 * This works and performs better than bridging a physical
5694 * interface via the current FreeBSD vboxnetflt implementation.
5695 */
5696 if (!strncmp(pszBridgedIfName, RT_STR_TUPLE("tap"))) {
5697 hrc = i_attachToTapInterface(aNetworkAdapter);
5698 if (FAILED(hrc))
5699 {
5700 switch (hrc)
5701 {
5702 case E_ACCESSDENIED:
5703 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5704 "Failed to open '/dev/%s' for read/write access. Please check the "
5705 "permissions of that node, and that the net.link.tap.user_open "
5706 "sysctl is set. Either run 'chmod 0666 /dev/%s' or "
5707 "change the group of that node to vboxusers and make yourself "
5708 "a member of that group. Make sure that these changes are permanent."),
5709 pszBridgedIfName, pszBridgedIfName);
5710 default:
5711 AssertMsgFailed(("Could not attach to tap interface! Bad!\n"));
5712 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5713 "Failed to initialize Host Interface Networking"));
5714 }
5715 }
5716
5717 Assert((intptr_t)maTapFD[uInstance] >= 0);
5718 if ((intptr_t)maTapFD[uInstance] >= 0)
5719 {
5720 InsertConfigString(pLunL0, "Driver", "HostInterface");
5721 InsertConfigNode(pLunL0, "Config", &pCfg);
5722 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
5723 }
5724 break;
5725 }
5726# endif
5727 /** @todo Check for malformed names. */
5728 const char *pszTrunk = pszBridgedIfName;
5729
5730 /* Issue a warning if the interface is down */
5731 {
5732 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
5733 if (iSock >= 0)
5734 {
5735 struct ifreq Req;
5736 RT_ZERO(Req);
5737 RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pszBridgedIfName);
5738 if (ioctl(iSock, SIOCGIFFLAGS, &Req) >= 0)
5739 if ((Req.ifr_flags & IFF_UP) == 0)
5740 i_atVMRuntimeErrorCallbackF(0, "BridgedInterfaceDown",
5741 N_("Bridged interface %s is down. Guest will not be able to use this interface"),
5742 pszBridgedIfName);
5743
5744 close(iSock);
5745 }
5746 }
5747
5748# else
5749# error "PORTME (VBOX_WITH_NETFLT)"
5750# endif
5751
5752 InsertConfigString(pLunL0, "Driver", "IntNet");
5753 InsertConfigNode(pLunL0, "Config", &pCfg);
5754 InsertConfigString(pCfg, "Trunk", pszTrunk);
5755 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
5756 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure);
5757 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5758 char szNetwork[INTNET_MAX_NETWORK_NAME];
5759
5760# if defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN)
5761 /*
5762 * 'pszTrunk' contains just the interface name required in ring-0, while 'pszBridgedIfName' contains
5763 * interface name + optional description. We must not pass any description to the VM as it can differ
5764 * for the same interface name, eg: "nge0 - ethernet" (GUI) vs "nge0" (VBoxManage).
5765 */
5766 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszTrunk);
5767# else
5768 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszBridgedIfName);
5769# endif
5770 InsertConfigString(pCfg, "Network", szNetwork);
5771 networkName = Bstr(szNetwork);
5772 trunkName = Bstr(pszTrunk);
5773 trunkType = Bstr(TRUNKTYPE_NETFLT);
5774
5775 BOOL fSharedMacOnWire = false;
5776 hrc = hostInterface->COMGETTER(Wireless)(&fSharedMacOnWire);
5777 if (FAILED(hrc))
5778 {
5779 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Wireless) failed, hrc (0x%x)\n", hrc));
5780 H();
5781 }
5782 else if (fSharedMacOnWire)
5783 {
5784 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5785 Log(("Set SharedMacOnWire\n"));
5786 }
5787
5788# if defined(RT_OS_SOLARIS)
5789# if 0 /* bird: this is a bit questionable and might cause more trouble than its worth. */
5790 /* Zone access restriction, don't allow snooping the global zone. */
5791 zoneid_t ZoneId = getzoneid();
5792 if (ZoneId != GLOBAL_ZONEID)
5793 {
5794 InsertConfigInteger(pCfg, "IgnoreAllPromisc", true);
5795 }
5796# endif
5797# endif
5798
5799#elif defined(RT_OS_WINDOWS) /* not defined NetFlt */
5800 /* NOTHING TO DO HERE */
5801#elif defined(RT_OS_LINUX)
5802/// @todo aleksey: is there anything to be done here?
5803#elif defined(RT_OS_FREEBSD)
5804/** @todo FreeBSD: Check out this later (HIF networking). */
5805#else
5806# error "Port me"
5807#endif
5808 break;
5809 }
5810
5811 case NetworkAttachmentType_Internal:
5812 {
5813 hrc = aNetworkAdapter->COMGETTER(InternalNetwork)(bstr.asOutParam()); H();
5814 if (!bstr.isEmpty())
5815 {
5816 InsertConfigString(pLunL0, "Driver", "IntNet");
5817 InsertConfigNode(pLunL0, "Config", &pCfg);
5818 InsertConfigString(pCfg, "Network", bstr);
5819 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
5820 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5821 networkName = bstr;
5822 trunkType = Bstr(TRUNKTYPE_WHATEVER);
5823 }
5824 break;
5825 }
5826
5827 case NetworkAttachmentType_HostOnly:
5828 {
5829 InsertConfigString(pLunL0, "Driver", "IntNet");
5830 InsertConfigNode(pLunL0, "Config", &pCfg);
5831
5832 Bstr HostOnlyName;
5833 hrc = aNetworkAdapter->COMGETTER(HostOnlyInterface)(HostOnlyName.asOutParam());
5834 if (FAILED(hrc))
5835 {
5836 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(HostOnlyInterface) failed, hrc (0x%x)\n", hrc));
5837 H();
5838 }
5839
5840 Utf8Str HostOnlyNameUtf8(HostOnlyName);
5841 const char *pszHostOnlyName = HostOnlyNameUtf8.c_str();
5842 ComPtr<IHostNetworkInterface> hostInterface;
5843 rc = host->FindHostNetworkInterfaceByName(HostOnlyName.raw(),
5844 hostInterface.asOutParam());
5845 if (!SUCCEEDED(rc))
5846 {
5847 LogRel(("NetworkAttachmentType_HostOnly: FindByName failed, rc (0x%x)\n", rc));
5848 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5849 N_("Nonexistent host networking interface, name '%ls'"),
5850 HostOnlyName.raw());
5851 }
5852
5853 char szNetwork[INTNET_MAX_NETWORK_NAME];
5854 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszHostOnlyName);
5855
5856#if defined(RT_OS_WINDOWS)
5857# ifndef VBOX_WITH_NETFLT
5858 hrc = E_NOTIMPL;
5859 LogRel(("NetworkAttachmentType_HostOnly: Not Implemented\n"));
5860 H();
5861# else /* defined VBOX_WITH_NETFLT*/
5862 /** @todo r=bird: Put this in a function. */
5863
5864 HostNetworkInterfaceType_T eIfType;
5865 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
5866 if (FAILED(hrc))
5867 {
5868 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
5869 H();
5870 }
5871
5872 if (eIfType != HostNetworkInterfaceType_HostOnly)
5873 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5874 N_("Interface ('%ls') is not a Host-Only Adapter interface"),
5875 HostOnlyName.raw());
5876
5877 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
5878 if (FAILED(hrc))
5879 {
5880 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
5881 H();
5882 }
5883 Guid hostIFGuid(bstr);
5884
5885 INetCfg *pNc;
5886 ComPtr<INetCfgComponent> pAdaptorComponent;
5887 LPWSTR pszApp;
5888 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
5889 Assert(hrc == S_OK);
5890 if (hrc != S_OK)
5891 {
5892 LogRel(("NetworkAttachmentType_HostOnly: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5893 H();
5894 }
5895
5896 /* get the adapter's INetCfgComponent*/
5897 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
5898 pAdaptorComponent.asOutParam());
5899 if (hrc != S_OK)
5900 {
5901 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5902 LogRel(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5903 H();
5904 }
5905# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
5906 char szTrunkName[INTNET_MAX_TRUNK_NAME];
5907 bool fNdis6 = false;
5908 wchar_t * pwszHelpText;
5909 hrc = pAdaptorComponent->GetHelpText(&pwszHelpText);
5910 Assert(hrc == S_OK);
5911 if (hrc == S_OK)
5912 {
5913 Log(("help-text=%ls\n", pwszHelpText));
5914 if (!wcscmp(pwszHelpText, L"VirtualBox NDIS 6.0 Miniport Driver"))
5915 fNdis6 = true;
5916 CoTaskMemFree(pwszHelpText);
5917 }
5918 if (fNdis6)
5919 {
5920 strncpy(szTrunkName, pszHostOnlyName, sizeof(szTrunkName) - 1);
5921 Log(("trunk=%s\n", szTrunkName));
5922 }
5923 else
5924 {
5925 char *pszTrunkName = szTrunkName;
5926 wchar_t * pswzBindName;
5927 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
5928 Assert(hrc == S_OK);
5929 if (hrc == S_OK)
5930 {
5931 int cwBindName = (int)wcslen(pswzBindName) + 1;
5932 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
5933 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
5934 {
5935 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
5936 pszTrunkName += cbFullBindNamePrefix-1;
5937 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
5938 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
5939 {
5940 DWORD err = GetLastError();
5941 hrc = HRESULT_FROM_WIN32(err);
5942 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
5943 hrc, hrc, err));
5944 }
5945 }
5946 else
5947 {
5948 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: insufficient szTrunkName buffer space\n"));
5949 /** @todo set appropriate error code */
5950 hrc = E_FAIL;
5951 }
5952
5953 if (hrc != S_OK)
5954 {
5955 AssertFailed();
5956 CoTaskMemFree(pswzBindName);
5957 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5958 H();
5959 }
5960 }
5961 else
5962 {
5963 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5964 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n",
5965 hrc, hrc));
5966 H();
5967 }
5968
5969
5970 CoTaskMemFree(pswzBindName);
5971 }
5972
5973 trunkType = TRUNKTYPE_NETADP;
5974 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
5975
5976 pAdaptorComponent.setNull();
5977 /* release the pNc finally */
5978 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5979
5980 const char *pszTrunk = szTrunkName;
5981
5982 InsertConfigString(pCfg, "Trunk", pszTrunk);
5983 InsertConfigString(pCfg, "Network", szNetwork);
5984 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure); /** @todo why is this
5985 windows only?? */
5986 networkName = Bstr(szNetwork);
5987 trunkName = Bstr(pszTrunk);
5988# endif /* defined VBOX_WITH_NETFLT*/
5989#elif defined(RT_OS_DARWIN)
5990 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
5991 InsertConfigString(pCfg, "Network", szNetwork);
5992 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
5993 networkName = Bstr(szNetwork);
5994 trunkName = Bstr(pszHostOnlyName);
5995 trunkType = TRUNKTYPE_NETADP;
5996#else
5997 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
5998 InsertConfigString(pCfg, "Network", szNetwork);
5999 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
6000 networkName = Bstr(szNetwork);
6001 trunkName = Bstr(pszHostOnlyName);
6002 trunkType = TRUNKTYPE_NETFLT;
6003#endif
6004 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
6005
6006#if !defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
6007
6008 Bstr tmpAddr, tmpMask;
6009
6010 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPAddress",
6011 pszHostOnlyName).raw(),
6012 tmpAddr.asOutParam());
6013 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty())
6014 {
6015 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPNetMask",
6016 pszHostOnlyName).raw(),
6017 tmpMask.asOutParam());
6018 if (SUCCEEDED(hrc) && !tmpMask.isEmpty())
6019 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
6020 tmpMask.raw());
6021 else
6022 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
6023 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
6024 }
6025 else
6026 {
6027 /* Grab the IP number from the 'vboxnetX' instance number (see netif.h) */
6028 hrc = hostInterface->EnableStaticIPConfig(getDefaultIPv4Address(Bstr(pszHostOnlyName)).raw(),
6029 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
6030 }
6031
6032 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
6033
6034 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6Address",
6035 pszHostOnlyName).raw(),
6036 tmpAddr.asOutParam());
6037 if (SUCCEEDED(hrc))
6038 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6NetMask", pszHostOnlyName).raw(),
6039 tmpMask.asOutParam());
6040 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty() && !tmpMask.isEmpty())
6041 {
6042 hrc = hostInterface->EnableStaticIPConfigV6(tmpAddr.raw(),
6043 Utf8Str(tmpMask).toUInt32());
6044 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
6045 }
6046#endif
6047 break;
6048 }
6049
6050 case NetworkAttachmentType_Generic:
6051 {
6052 hrc = aNetworkAdapter->COMGETTER(GenericDriver)(bstr.asOutParam()); H();
6053 SafeArray<BSTR> names;
6054 SafeArray<BSTR> values;
6055 hrc = aNetworkAdapter->GetProperties(Bstr().raw(),
6056 ComSafeArrayAsOutParam(names),
6057 ComSafeArrayAsOutParam(values)); H();
6058
6059 InsertConfigString(pLunL0, "Driver", bstr);
6060 InsertConfigNode(pLunL0, "Config", &pCfg);
6061 for (size_t ii = 0; ii < names.size(); ++ii)
6062 {
6063 if (values[ii] && *values[ii])
6064 {
6065 Utf8Str name = names[ii];
6066 Utf8Str value = values[ii];
6067 InsertConfigString(pCfg, name.c_str(), value);
6068 }
6069 }
6070 break;
6071 }
6072
6073 case NetworkAttachmentType_NATNetwork:
6074 {
6075 hrc = aNetworkAdapter->COMGETTER(NATNetwork)(bstr.asOutParam()); H();
6076 if (!bstr.isEmpty())
6077 {
6078 /** @todo add intnet prefix to separate namespaces, and add trunk if dealing with vboxnatX */
6079 InsertConfigString(pLunL0, "Driver", "IntNet");
6080 InsertConfigNode(pLunL0, "Config", &pCfg);
6081 InsertConfigString(pCfg, "Network", bstr);
6082 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
6083 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
6084 networkName = bstr;
6085 trunkType = Bstr(TRUNKTYPE_WHATEVER);
6086 }
6087 break;
6088 }
6089
6090#ifdef VBOX_WITH_CLOUD_NET
6091 case NetworkAttachmentType_Cloud:
6092 {
6093 static const char *s_pszCloudExtPackName = "Oracle VM VirtualBox Extension Pack";
6094 /*
6095 * Cloud network attachments do not work wihout installed extpack.
6096 * Without extpack support they won't work either.
6097 */
6098# ifdef VBOX_WITH_EXTPACK
6099 if (!mptrExtPackManager->i_isExtPackUsable(s_pszCloudExtPackName))
6100# endif
6101 {
6102 return VMSetError(VMR3GetVM(mpUVM), VERR_NOT_FOUND, RT_SRC_POS,
6103 N_("Implementation of the cloud network attachment not found!\n"
6104 "To fix this problem, either install the '%s' or switch to "
6105 "another network attachment type in the VM settings.\n"
6106 ),
6107 s_pszCloudExtPackName);
6108 }
6109
6110 ComPtr<ICloudNetwork> network;
6111 hrc = aNetworkAdapter->COMGETTER(CloudNetwork)(bstr.asOutParam()); H();
6112 hrc = pMachine->COMGETTER(Name)(mGateways.mTargetVM.asOutParam()); H();
6113 hrc = virtualBox->FindCloudNetworkByName(bstr.raw(), network.asOutParam()); H();
6114 hrc = startGateways(virtualBox, network, mGateways); H();
6115 InsertConfigBytes(pDevCfg, "MAC", &mGateways.mCloudMacAddress, sizeof(mGateways.mCloudMacAddress));
6116 if (!bstr.isEmpty())
6117 {
6118 InsertConfigString(pLunL0, "Driver", "IntNet");
6119 InsertConfigNode(pLunL0, "Config", &pCfg);
6120 InsertConfigString(pCfg, "Network", BstrFmt("cloud-%ls", bstr.raw()));
6121 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
6122 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
6123 networkName = bstr;
6124 trunkType = Bstr(TRUNKTYPE_WHATEVER);
6125 }
6126 break;
6127 }
6128#endif /* VBOX_WITH_CLOUD_NET */
6129
6130 default:
6131 AssertMsgFailed(("should not get here!\n"));
6132 break;
6133 }
6134
6135 /*
6136 * Attempt to attach the driver.
6137 */
6138 switch (eAttachmentType)
6139 {
6140 case NetworkAttachmentType_Null:
6141 break;
6142
6143 case NetworkAttachmentType_Bridged:
6144 case NetworkAttachmentType_Internal:
6145 case NetworkAttachmentType_HostOnly:
6146 case NetworkAttachmentType_NAT:
6147 case NetworkAttachmentType_Generic:
6148 case NetworkAttachmentType_NATNetwork:
6149#ifdef VBOX_WITH_CLOUD_NET
6150 case NetworkAttachmentType_Cloud:
6151#endif /* VBOX_WITH_CLOUD_NET */
6152 {
6153 if (SUCCEEDED(hrc) && RT_SUCCESS(rc))
6154 {
6155 if (fAttachDetach)
6156 {
6157 rc = PDMR3DriverAttach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/, NULL /* ppBase */);
6158 //AssertRC(rc);
6159 }
6160
6161 {
6162 /** @todo pritesh: get the dhcp server name from the
6163 * previous network configuration and then stop the server
6164 * else it may conflict with the dhcp server running with
6165 * the current attachment type
6166 */
6167 /* Stop the hostonly DHCP Server */
6168 }
6169
6170 /*
6171 * NAT networks start their DHCP server theirself, see NATNetwork::Start()
6172 */
6173 if ( !networkName.isEmpty()
6174 && eAttachmentType != NetworkAttachmentType_NATNetwork)
6175 {
6176 /*
6177 * Until we implement service reference counters DHCP Server will be stopped
6178 * by DHCPServerRunner destructor.
6179 */
6180 ComPtr<IDHCPServer> dhcpServer;
6181 hrc = virtualBox->FindDHCPServerByNetworkName(networkName.raw(),
6182 dhcpServer.asOutParam());
6183 if (SUCCEEDED(hrc))
6184 {
6185 /* there is a DHCP server available for this network */
6186 BOOL fEnabledDhcp;
6187 hrc = dhcpServer->COMGETTER(Enabled)(&fEnabledDhcp);
6188 if (FAILED(hrc))
6189 {
6190 LogRel(("DHCP svr: COMGETTER(Enabled) failed, hrc (%Rhrc)\n", hrc));
6191 H();
6192 }
6193
6194 if (fEnabledDhcp)
6195 hrc = dhcpServer->Start(trunkName.raw(),
6196 trunkType.raw());
6197 }
6198 else
6199 hrc = S_OK;
6200 }
6201 }
6202
6203 break;
6204 }
6205
6206 default:
6207 AssertMsgFailed(("should not get here!\n"));
6208 break;
6209 }
6210
6211 meAttachmentType[uInstance] = eAttachmentType;
6212 }
6213 catch (ConfigError &x)
6214 {
6215 // InsertConfig threw something:
6216 return x.m_vrc;
6217 }
6218
6219#undef H
6220
6221 return VINF_SUCCESS;
6222}
6223
6224
6225/**
6226 * Configures the serial port at the given CFGM node with the supplied parameters.
6227 *
6228 * @returns VBox status code.
6229 * @param pInst The instance CFGM node.
6230 * @param ePortMode The port mode to sue.
6231 * @param pszPath The serial port path.
6232 * @param fServer Flag whether the port should act as a server
6233 * for the pipe and TCP mode or connect as a client.
6234 */
6235int Console::i_configSerialPort(PCFGMNODE pInst, PortMode_T ePortMode, const char *pszPath, bool fServer)
6236{
6237 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
6238 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */
6239 PCFGMNODE pLunL1Cfg = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/Config */
6240
6241 try
6242 {
6243 InsertConfigNode(pInst, "LUN#0", &pLunL0);
6244 if (ePortMode == PortMode_HostPipe)
6245 {
6246 InsertConfigString(pLunL0, "Driver", "Char");
6247 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
6248 InsertConfigString(pLunL1, "Driver", "NamedPipe");
6249 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
6250 InsertConfigString(pLunL1Cfg, "Location", pszPath);
6251 InsertConfigInteger(pLunL1Cfg, "IsServer", fServer);
6252 }
6253 else if (ePortMode == PortMode_HostDevice)
6254 {
6255 InsertConfigString(pLunL0, "Driver", "Host Serial");
6256 InsertConfigNode(pLunL0, "Config", &pLunL1);
6257 InsertConfigString(pLunL1, "DevicePath", pszPath);
6258 }
6259 else if (ePortMode == PortMode_TCP)
6260 {
6261 InsertConfigString(pLunL0, "Driver", "Char");
6262 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
6263 InsertConfigString(pLunL1, "Driver", "TCP");
6264 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
6265 InsertConfigString(pLunL1Cfg, "Location", pszPath);
6266 InsertConfigInteger(pLunL1Cfg, "IsServer", fServer);
6267 }
6268 else if (ePortMode == PortMode_RawFile)
6269 {
6270 InsertConfigString(pLunL0, "Driver", "Char");
6271 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
6272 InsertConfigString(pLunL1, "Driver", "RawFile");
6273 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
6274 InsertConfigString(pLunL1Cfg, "Location", pszPath);
6275 }
6276 }
6277 catch (ConfigError &x)
6278 {
6279 /* InsertConfig threw something */
6280 return x.m_vrc;
6281 }
6282
6283 return VINF_SUCCESS;
6284}
6285
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