VirtualBox

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

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

Audio/ValKit: Made the Validation Kit audio driver selectable in Main (via extra-data); saves a (dummy) LUN when enabled. bugref:10008

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

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