VirtualBox

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

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

Intel IOMMU: bugref:9967 ConsoleImpl2: When an Intel IOMMU is present, the I/O APIC chipset type must be compatible with the DMAR to allow the guest to program RTEs and generate MSIs that are capable of being remapped.

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