VirtualBox

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

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

Intel IOMMU: bugref:9967 ConsoleImpl2, DevIoApic: When Main configures the PCI address of the I/O APIC to the BusAssignmentManager, pass it on to the I/O APIC device as well.
This will allow us to use different PCI addresses for AMD and Intel IOMMUs if required.

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