VirtualBox

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

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

Main: Try fix VRDP-input-always-disabled regression from r120203+r120206. [build fix] bugref:7820 bugref:9890

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

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