VirtualBox

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

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

Main: Try fix VRDP-input-always-disabled regression from r120203+r120206. 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 89580 2021-06-09 13:22:55Z 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 HRESULT hrc;
3702
3703 InsertConfigString(pLUN, "Driver", "AUDIO");
3704
3705 PCFGMNODE pCfg;
3706 InsertConfigNode(pLUN, "Config", &pCfg);
3707 InsertConfigString(pCfg, "DriverName", pszDrvName);
3708 InsertConfigInteger(pCfg, "InputEnabled", fAudioEnabledIn);
3709 InsertConfigInteger(pCfg, "OutputEnabled", fAudioEnabledOut);
3710
3711 Utf8Str strTmp;
3712 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/Audio/Debug/Enabled", &strTmp);
3713 const uint64_t fDebugEnabled = strTmp.equalsIgnoreCase("true") || strTmp.equalsIgnoreCase("1");
3714 if (fDebugEnabled)
3715 {
3716 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
3717
3718 Utf8Str strDebugPathOut;
3719 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/Audio/Debug/PathOut", &strDebugPathOut);
3720 InsertConfigString(pCfg, "DebugPathOut", strDebugPathOut.c_str());
3721 }
3722
3723 /*
3724 * PCM input parameters (playback + recording).
3725 * We have host driver specific ones as: VBoxInternal2/Audio/<DrvName>/<Value>
3726 * And global ones for all host drivers: VBoxInternal2/Audio/<Value>
3727 */
3728 for (unsigned iDir = 0; iDir < 2; iDir++)
3729 {
3730 static const struct
3731 {
3732 const char *pszExtraName;
3733 const char *pszCfgmName;
3734 } s_aToCopy[] =
3735 { /* PCM parameters: */
3736 { "PCMSampleBit", "PCMSampleBit" },
3737 { "PCMSampleHz", "PCMSampleHz" },
3738 { "PCMSampleSigned", "PCMSampleSigned" },
3739 { "PCMSampleSwapEndian", "PCMSampleSwapEndian" },
3740 { "PCMSampleChannels", "PCMSampleChannels" },
3741 /* Buffering stuff: */
3742 { "PeriodSizeMs", "PeriodSizeMs" },
3743 { "BufferSizeMs", "BufferSizeMs" },
3744 { "PreBufferSizeMs", "PreBufferSizeMs" },
3745 };
3746
3747 PCFGMNODE pDirNode = NULL;
3748 const char *pszDir = iDir == 0 ? "In" : "Out";
3749 for (size_t i = 0; i < RT_ELEMENTS(s_aToCopy); i++)
3750 {
3751 char szExtra[128];
3752 RTStrPrintf(szExtra, sizeof(szExtra), "VBoxInternal2/Audio/%s/%s%s", pszDrvName, s_aToCopy[i].pszExtraName, pszDir);
3753 GetExtraDataBoth(pVirtualBox, pMachine, szExtra, &strTmp); /* throws hrc */
3754 if (strTmp.isEmpty())
3755 {
3756 RTStrPrintf(szExtra, sizeof(szExtra), "VBoxInternal2/Audio/%s%s", s_aToCopy[i].pszExtraName, pszDir);
3757 GetExtraDataBoth(pVirtualBox, pMachine, szExtra, &strTmp);
3758 if (strTmp.isEmpty())
3759 continue;
3760 }
3761
3762 uint32_t uValue;
3763 int vrc = RTStrToUInt32Full(strTmp.c_str(), 0, &uValue);
3764 if (RT_SUCCESS(vrc))
3765 {
3766 if (!pDirNode)
3767 InsertConfigNode(pCfg, pszDir, &pDirNode);
3768 InsertConfigInteger(pDirNode, s_aToCopy[i].pszCfgmName, uValue);
3769 }
3770 else
3771 LogRel(("Ignoring malformed 32-bit unsigned integer config value '%s' = '%s': %Rrc\n", szExtra, strTmp.c_str(), vrc));
3772 }
3773 }
3774
3775 PCFGMNODE pLunL1;
3776 InsertConfigNode(pLUN, "AttachedDriver", &pLunL1);
3777 InsertConfigString(pLunL1, "Driver", pszDrvName);
3778 InsertConfigNode(pLunL1, "Config", &pCfg);
3779
3780#ifdef RT_OS_WINDOWS
3781 if (strcmp(pszDrvName, "HostAudioWas") == 0)
3782 {
3783 Bstr bstrTmp;
3784 hrc = pMachine->COMGETTER(Id)(bstrTmp.asOutParam()); H();
3785 InsertConfigString(pCfg, "VmUuid", bstrTmp);
3786 }
3787#endif
3788
3789#if defined(RT_OS_WINDOWS) || defined(RT_OS_LINUX)
3790 if ( strcmp(pszDrvName, "HostAudioWas") == 0
3791 || strcmp(pszDrvName, "PulseAudio") == 0)
3792 {
3793 Bstr bstrTmp;
3794 hrc = pMachine->COMGETTER(Name)(bstrTmp.asOutParam()); H();
3795 InsertConfigString(pCfg, "VmName", bstrTmp);
3796 }
3797#endif
3798
3799 LogFlowFunc(("szDrivName=%s\n", pszDrvName));
3800
3801#undef H
3802}
3803
3804/**
3805 * Applies the CFGM overlay as specified by VBoxInternal/XXX extra data
3806 * values.
3807 *
3808 * @returns VBox status code.
3809 * @param pRoot The root of the configuration tree.
3810 * @param pVirtualBox Pointer to the IVirtualBox interface.
3811 * @param pMachine Pointer to the IMachine interface.
3812 */
3813/* static */
3814int Console::i_configCfgmOverlay(PCFGMNODE pRoot, IVirtualBox *pVirtualBox, IMachine *pMachine)
3815{
3816 /*
3817 * CFGM overlay handling.
3818 *
3819 * Here we check the extra data entries for CFGM values
3820 * and create the nodes and insert the values on the fly. Existing
3821 * values will be removed and reinserted. CFGM is typed, so by default
3822 * we will guess whether it's a string or an integer (byte arrays are
3823 * not currently supported). It's possible to override this autodetection
3824 * by adding "string:", "integer:" or "bytes:" (future).
3825 *
3826 * We first perform a run on global extra data, then on the machine
3827 * extra data to support global settings with local overrides.
3828 */
3829 int rc = VINF_SUCCESS;
3830 bool fFirst = true;
3831 try
3832 {
3833 /** @todo add support for removing nodes and byte blobs. */
3834 /*
3835 * Get the next key
3836 */
3837 SafeArray<BSTR> aGlobalExtraDataKeys;
3838 SafeArray<BSTR> aMachineExtraDataKeys;
3839 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
3840 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
3841
3842 // remember the no. of global values so we can call the correct method below
3843 size_t cGlobalValues = aGlobalExtraDataKeys.size();
3844
3845 hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
3846 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
3847
3848 // build a combined list from global keys...
3849 std::list<Utf8Str> llExtraDataKeys;
3850
3851 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); ++i)
3852 llExtraDataKeys.push_back(Utf8Str(aGlobalExtraDataKeys[i]));
3853 // ... and machine keys
3854 for (size_t i = 0; i < aMachineExtraDataKeys.size(); ++i)
3855 llExtraDataKeys.push_back(Utf8Str(aMachineExtraDataKeys[i]));
3856
3857 size_t i2 = 0;
3858 for (std::list<Utf8Str>::const_iterator it = llExtraDataKeys.begin();
3859 it != llExtraDataKeys.end();
3860 ++it, ++i2)
3861 {
3862 const Utf8Str &strKey = *it;
3863
3864 /*
3865 * We only care about keys starting with "VBoxInternal/" (skip "G:" or "M:")
3866 */
3867 if (!strKey.startsWith("VBoxInternal/"))
3868 continue;
3869
3870 const char *pszExtraDataKey = strKey.c_str() + sizeof("VBoxInternal/") - 1;
3871
3872 // get the value
3873 Bstr bstrExtraDataValue;
3874 if (i2 < cGlobalValues)
3875 // this is still one of the global values:
3876 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
3877 bstrExtraDataValue.asOutParam());
3878 else
3879 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
3880 bstrExtraDataValue.asOutParam());
3881 if (FAILED(hrc))
3882 LogRel(("Warning: Cannot get extra data key %s, rc = %Rhrc\n", strKey.c_str(), hrc));
3883
3884 if (fFirst)
3885 {
3886 fFirst = false;
3887 LogRel(("Extradata overrides:\n"));
3888 }
3889 LogRel((" %s=\"%ls\"%s\n", strKey.c_str(), bstrExtraDataValue.raw(), i2 < cGlobalValues ? " (global)" : ""));
3890
3891 /*
3892 * The key will be in the format "Node1/Node2/Value" or simply "Value".
3893 * Split the two and get the node, delete the value and create the node
3894 * if necessary.
3895 */
3896 PCFGMNODE pNode;
3897 const char *pszCFGMValueName = strrchr(pszExtraDataKey, '/');
3898 if (pszCFGMValueName)
3899 {
3900 /* terminate the node and advance to the value (Utf8Str might not
3901 offically like this but wtf) */
3902 *(char *)pszCFGMValueName = '\0';
3903 ++pszCFGMValueName;
3904
3905 /* does the node already exist? */
3906 pNode = CFGMR3GetChild(pRoot, pszExtraDataKey);
3907 if (pNode)
3908 CFGMR3RemoveValue(pNode, pszCFGMValueName);
3909 else
3910 {
3911 /* create the node */
3912 rc = CFGMR3InsertNode(pRoot, pszExtraDataKey, &pNode);
3913 if (RT_FAILURE(rc))
3914 {
3915 AssertLogRelMsgRC(rc, ("failed to insert node '%s'\n", pszExtraDataKey));
3916 continue;
3917 }
3918 Assert(pNode);
3919 }
3920 }
3921 else
3922 {
3923 /* root value (no node path). */
3924 pNode = pRoot;
3925 pszCFGMValueName = pszExtraDataKey;
3926 pszExtraDataKey--;
3927 CFGMR3RemoveValue(pNode, pszCFGMValueName);
3928 }
3929
3930 /*
3931 * Now let's have a look at the value.
3932 * Empty strings means that we should remove the value, which we've
3933 * already done above.
3934 */
3935 Utf8Str strCFGMValueUtf8(bstrExtraDataValue);
3936 if (!strCFGMValueUtf8.isEmpty())
3937 {
3938 uint64_t u64Value;
3939
3940 /* check for type prefix first. */
3941 if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("string:")))
3942 InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8.c_str() + sizeof("string:") - 1);
3943 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("integer:")))
3944 {
3945 rc = RTStrToUInt64Full(strCFGMValueUtf8.c_str() + sizeof("integer:") - 1, 0, &u64Value);
3946 if (RT_SUCCESS(rc))
3947 rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
3948 }
3949 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("bytes:")))
3950 {
3951 char const *pszBase64 = strCFGMValueUtf8.c_str() + sizeof("bytes:") - 1;
3952 ssize_t cbValue = RTBase64DecodedSize(pszBase64, NULL);
3953 if (cbValue > 0)
3954 {
3955 void *pvBytes = RTMemTmpAlloc(cbValue);
3956 if (pvBytes)
3957 {
3958 rc = RTBase64Decode(pszBase64, pvBytes, cbValue, NULL, NULL);
3959 if (RT_SUCCESS(rc))
3960 rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, pvBytes, cbValue);
3961 RTMemTmpFree(pvBytes);
3962 }
3963 else
3964 rc = VERR_NO_TMP_MEMORY;
3965 }
3966 else if (cbValue == 0)
3967 rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, NULL, 0);
3968 else
3969 rc = VERR_INVALID_BASE64_ENCODING;
3970 }
3971 /* auto detect type. */
3972 else if (RT_SUCCESS(RTStrToUInt64Full(strCFGMValueUtf8.c_str(), 0, &u64Value)))
3973 rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
3974 else
3975 InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8);
3976 AssertLogRelMsgRCBreak(rc, ("failed to insert CFGM value '%s' to key '%s'\n",
3977 strCFGMValueUtf8.c_str(), pszExtraDataKey));
3978 }
3979 }
3980 }
3981 catch (ConfigError &x)
3982 {
3983 // InsertConfig threw something:
3984 return x.m_vrc;
3985 }
3986 return rc;
3987}
3988
3989/**
3990 * Dumps the API settings tweaks as specified by VBoxInternal2/XXX extra data
3991 * values.
3992 *
3993 * @returns VBox status code.
3994 * @param pVirtualBox Pointer to the IVirtualBox interface.
3995 * @param pMachine Pointer to the IMachine interface.
3996 */
3997/* static */
3998int Console::i_configDumpAPISettingsTweaks(IVirtualBox *pVirtualBox, IMachine *pMachine)
3999{
4000 {
4001 SafeArray<BSTR> aGlobalExtraDataKeys;
4002 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
4003 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
4004 bool hasKey = false;
4005 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); i++)
4006 {
4007 Utf8Str strKey(aGlobalExtraDataKeys[i]);
4008 if (!strKey.startsWith("VBoxInternal2/"))
4009 continue;
4010
4011 Bstr bstrValue;
4012 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
4013 bstrValue.asOutParam());
4014 if (FAILED(hrc))
4015 continue;
4016 if (!hasKey)
4017 LogRel(("Global extradata API settings:\n"));
4018 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
4019 hasKey = true;
4020 }
4021 }
4022
4023 {
4024 SafeArray<BSTR> aMachineExtraDataKeys;
4025 HRESULT hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
4026 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
4027 bool hasKey = false;
4028 for (size_t i = 0; i < aMachineExtraDataKeys.size(); i++)
4029 {
4030 Utf8Str strKey(aMachineExtraDataKeys[i]);
4031 if (!strKey.startsWith("VBoxInternal2/"))
4032 continue;
4033
4034 Bstr bstrValue;
4035 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
4036 bstrValue.asOutParam());
4037 if (FAILED(hrc))
4038 continue;
4039 if (!hasKey)
4040 LogRel(("Per-VM extradata API settings:\n"));
4041 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
4042 hasKey = true;
4043 }
4044 }
4045
4046 return VINF_SUCCESS;
4047}
4048
4049int Console::i_configGraphicsController(PCFGMNODE pDevices,
4050 const GraphicsControllerType_T enmGraphicsController,
4051 BusAssignmentManager *pBusMgr,
4052 const ComPtr<IMachine> &ptrMachine,
4053 const ComPtr<IGraphicsAdapter> &ptrGraphicsAdapter,
4054 const ComPtr<IBIOSSettings> &ptrBiosSettings,
4055 bool fHMEnabled)
4056{
4057 // InsertConfig* throws
4058 try
4059 {
4060 PCFGMNODE pDev, pInst, pCfg, pLunL0;
4061 HRESULT hrc;
4062 Bstr bstr;
4063 const char *pcszDevice = "vga";
4064
4065#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4066 InsertConfigNode(pDevices, pcszDevice, &pDev);
4067 InsertConfigNode(pDev, "0", &pInst);
4068 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
4069
4070 hrc = pBusMgr->assignPCIDevice(pcszDevice, pInst); H();
4071 InsertConfigNode(pInst, "Config", &pCfg);
4072 ULONG cVRamMBs;
4073 hrc = ptrGraphicsAdapter->COMGETTER(VRAMSize)(&cVRamMBs); H();
4074 InsertConfigInteger(pCfg, "VRamSize", cVRamMBs * _1M);
4075 ULONG cMonitorCount;
4076 hrc = ptrGraphicsAdapter->COMGETTER(MonitorCount)(&cMonitorCount); H();
4077 InsertConfigInteger(pCfg, "MonitorCount", cMonitorCount);
4078#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
4079 InsertConfigInteger(pCfg, "R0Enabled", fHMEnabled);
4080#else
4081 NOREF(fHMEnabled);
4082#endif
4083 BOOL f3DEnabled;
4084 hrc = ptrGraphicsAdapter->COMGETTER(Accelerate3DEnabled)(&f3DEnabled); H();
4085 InsertConfigInteger(pCfg, "3DEnabled", f3DEnabled);
4086
4087 i_attachStatusDriver(pInst, DeviceType_Graphics3D, 0, 0, NULL, NULL, NULL, 0);
4088
4089#ifdef VBOX_WITH_VMSVGA
4090 if ( enmGraphicsController == GraphicsControllerType_VMSVGA
4091 || enmGraphicsController == GraphicsControllerType_VBoxSVGA)
4092 {
4093 InsertConfigInteger(pCfg, "VMSVGAEnabled", true);
4094 if (enmGraphicsController == GraphicsControllerType_VMSVGA)
4095 {
4096 InsertConfigInteger(pCfg, "VMSVGAPciBarLayout", true);
4097 InsertConfigInteger(pCfg, "VMSVGAPciId", true);
4098 }
4099# ifdef VBOX_WITH_VMSVGA3D
4100 InsertConfigInteger(pCfg, "VMSVGA3dEnabled", f3DEnabled);
4101# else
4102 LogRel(("VMSVGA3d not available in this build!\n"));
4103# endif /* VBOX_WITH_VMSVGA3D */
4104 }
4105#else
4106 RT_NOREF(enmGraphicsController);
4107#endif /* VBOX_WITH_VMSVGA */
4108
4109 /* Custom VESA mode list */
4110 unsigned cModes = 0;
4111 for (unsigned iMode = 1; iMode <= 16; ++iMode)
4112 {
4113 char szExtraDataKey[sizeof("CustomVideoModeXX")];
4114 RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%u", iMode);
4115 hrc = ptrMachine->GetExtraData(Bstr(szExtraDataKey).raw(), bstr.asOutParam()); H();
4116 if (bstr.isEmpty())
4117 break;
4118 InsertConfigString(pCfg, szExtraDataKey, bstr);
4119 ++cModes;
4120 }
4121 InsertConfigInteger(pCfg, "CustomVideoModes", cModes);
4122
4123 /* VESA height reduction */
4124 ULONG ulHeightReduction;
4125 IFramebuffer *pFramebuffer = NULL;
4126 hrc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
4127 if (SUCCEEDED(hrc) && pFramebuffer)
4128 {
4129 hrc = pFramebuffer->COMGETTER(HeightReduction)(&ulHeightReduction); H();
4130 pFramebuffer->Release();
4131 pFramebuffer = NULL;
4132 }
4133 else
4134 {
4135 /* If framebuffer is not available, there is no height reduction. */
4136 ulHeightReduction = 0;
4137 }
4138 InsertConfigInteger(pCfg, "HeightReduction", ulHeightReduction);
4139
4140 /*
4141 * BIOS logo
4142 */
4143 BOOL fFadeIn;
4144 hrc = ptrBiosSettings->COMGETTER(LogoFadeIn)(&fFadeIn); H();
4145 InsertConfigInteger(pCfg, "FadeIn", fFadeIn ? 1 : 0);
4146 BOOL fFadeOut;
4147 hrc = ptrBiosSettings->COMGETTER(LogoFadeOut)(&fFadeOut); H();
4148 InsertConfigInteger(pCfg, "FadeOut", fFadeOut ? 1: 0);
4149 ULONG logoDisplayTime;
4150 hrc = ptrBiosSettings->COMGETTER(LogoDisplayTime)(&logoDisplayTime); H();
4151 InsertConfigInteger(pCfg, "LogoTime", logoDisplayTime);
4152 Bstr logoImagePath;
4153 hrc = ptrBiosSettings->COMGETTER(LogoImagePath)(logoImagePath.asOutParam()); H();
4154 InsertConfigString(pCfg, "LogoFile", Utf8Str(!logoImagePath.isEmpty() ? logoImagePath : "") );
4155
4156 /*
4157 * Boot menu
4158 */
4159 BIOSBootMenuMode_T eBootMenuMode;
4160 int iShowBootMenu;
4161 hrc = ptrBiosSettings->COMGETTER(BootMenuMode)(&eBootMenuMode); H();
4162 switch (eBootMenuMode)
4163 {
4164 case BIOSBootMenuMode_Disabled: iShowBootMenu = 0; break;
4165 case BIOSBootMenuMode_MenuOnly: iShowBootMenu = 1; break;
4166 default: iShowBootMenu = 2; break;
4167 }
4168 InsertConfigInteger(pCfg, "ShowBootMenu", iShowBootMenu);
4169
4170 /* Attach the display. */
4171 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4172 InsertConfigString(pLunL0, "Driver", "MainDisplay");
4173 InsertConfigNode(pLunL0, "Config", &pCfg);
4174 Display *pDisplay = mDisplay;
4175 InsertConfigInteger(pCfg, "Object", (uintptr_t)pDisplay);
4176 }
4177 catch (ConfigError &x)
4178 {
4179 // InsertConfig threw something:
4180 return x.m_vrc;
4181 }
4182
4183#undef H
4184
4185 return VINF_SUCCESS;
4186}
4187
4188
4189/**
4190 * Ellipsis to va_list wrapper for calling setVMRuntimeErrorCallback.
4191 */
4192void Console::i_atVMRuntimeErrorCallbackF(uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)
4193{
4194 va_list va;
4195 va_start(va, pszFormat);
4196 i_atVMRuntimeErrorCallback(NULL, this, fFlags, pszErrorId, pszFormat, va);
4197 va_end(va);
4198}
4199
4200/* XXX introduce RT format specifier */
4201static uint64_t formatDiskSize(uint64_t u64Size, const char **pszUnit)
4202{
4203 if (u64Size > INT64_C(5000)*_1G)
4204 {
4205 *pszUnit = "TB";
4206 return u64Size / _1T;
4207 }
4208 else if (u64Size > INT64_C(5000)*_1M)
4209 {
4210 *pszUnit = "GB";
4211 return u64Size / _1G;
4212 }
4213 else
4214 {
4215 *pszUnit = "MB";
4216 return u64Size / _1M;
4217 }
4218}
4219
4220/**
4221 * Checks the location of the given medium for known bugs affecting the usage
4222 * of the host I/O cache setting.
4223 *
4224 * @returns VBox status code.
4225 * @param pMedium The medium to check.
4226 * @param pfUseHostIOCache Where to store the suggested host I/O cache setting.
4227 */
4228int Console::i_checkMediumLocation(IMedium *pMedium, bool *pfUseHostIOCache)
4229{
4230#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4231 /*
4232 * Some sanity checks.
4233 */
4234 RT_NOREF(pfUseHostIOCache);
4235 ComPtr<IMediumFormat> pMediumFormat;
4236 HRESULT hrc = pMedium->COMGETTER(MediumFormat)(pMediumFormat.asOutParam()); H();
4237 ULONG uCaps = 0;
4238 com::SafeArray <MediumFormatCapabilities_T> mediumFormatCap;
4239 hrc = pMediumFormat->COMGETTER(Capabilities)(ComSafeArrayAsOutParam(mediumFormatCap)); H();
4240
4241 for (ULONG j = 0; j < mediumFormatCap.size(); j++)
4242 uCaps |= mediumFormatCap[j];
4243
4244 if (uCaps & MediumFormatCapabilities_File)
4245 {
4246 Bstr strFile;
4247 hrc = pMedium->COMGETTER(Location)(strFile.asOutParam()); H();
4248 Utf8Str utfFile = Utf8Str(strFile);
4249 Bstr strSnap;
4250 ComPtr<IMachine> pMachine = i_machine();
4251 hrc = pMachine->COMGETTER(SnapshotFolder)(strSnap.asOutParam()); H();
4252 Utf8Str utfSnap = Utf8Str(strSnap);
4253 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
4254 RTFSTYPE enmFsTypeSnap = RTFSTYPE_UNKNOWN;
4255 int rc2 = RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
4256 AssertMsgRCReturn(rc2, ("Querying the file type of '%s' failed!\n", utfFile.c_str()), rc2);
4257 /* Ignore the error code. On error, the file system type is still 'unknown' so
4258 * none of the following paths are taken. This can happen for new VMs which
4259 * still don't have a snapshot folder. */
4260 (void)RTFsQueryType(utfSnap.c_str(), &enmFsTypeSnap);
4261 if (!mfSnapshotFolderDiskTypeShown)
4262 {
4263 LogRel(("File system of '%s' (snapshots) is %s\n",
4264 utfSnap.c_str(), RTFsTypeName(enmFsTypeSnap)));
4265 mfSnapshotFolderDiskTypeShown = true;
4266 }
4267 LogRel(("File system of '%s' is %s\n", utfFile.c_str(), RTFsTypeName(enmFsTypeFile)));
4268 LONG64 i64Size;
4269 hrc = pMedium->COMGETTER(LogicalSize)(&i64Size); H();
4270#ifdef RT_OS_WINDOWS
4271 if ( enmFsTypeFile == RTFSTYPE_FAT
4272 && i64Size >= _4G)
4273 {
4274 const char *pszUnit;
4275 uint64_t u64Print = formatDiskSize((uint64_t)i64Size, &pszUnit);
4276 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
4277 N_("The medium '%ls' has a logical size of %RU64%s "
4278 "but the file system the medium is located on seems "
4279 "to be FAT(32) which cannot handle files bigger than 4GB.\n"
4280 "We strongly recommend to put all your virtual disk images and "
4281 "the snapshot folder onto an NTFS partition"),
4282 strFile.raw(), u64Print, pszUnit);
4283 }
4284#else /* !RT_OS_WINDOWS */
4285 if ( enmFsTypeFile == RTFSTYPE_FAT
4286 || enmFsTypeFile == RTFSTYPE_EXT
4287 || enmFsTypeFile == RTFSTYPE_EXT2
4288 || enmFsTypeFile == RTFSTYPE_EXT3
4289 || enmFsTypeFile == RTFSTYPE_EXT4)
4290 {
4291 RTFILE file;
4292 int rc = RTFileOpen(&file, utfFile.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
4293 if (RT_SUCCESS(rc))
4294 {
4295 RTFOFF maxSize;
4296 /* Careful: This function will work only on selected local file systems! */
4297 rc = RTFileQueryMaxSizeEx(file, &maxSize);
4298 RTFileClose(file);
4299 if ( RT_SUCCESS(rc)
4300 && maxSize > 0
4301 && i64Size > (LONG64)maxSize)
4302 {
4303 const char *pszUnitSiz;
4304 const char *pszUnitMax;
4305 uint64_t u64PrintSiz = formatDiskSize((LONG64)i64Size, &pszUnitSiz);
4306 uint64_t u64PrintMax = formatDiskSize(maxSize, &pszUnitMax);
4307 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected", /* <= not exact but ... */
4308 N_("The medium '%ls' has a logical size of %RU64%s "
4309 "but the file system the medium is located on can "
4310 "only handle files up to %RU64%s in theory.\n"
4311 "We strongly recommend to put all your virtual disk "
4312 "images and the snapshot folder onto a proper "
4313 "file system (e.g. ext3) with a sufficient size"),
4314 strFile.raw(), u64PrintSiz, pszUnitSiz, u64PrintMax, pszUnitMax);
4315 }
4316 }
4317 }
4318#endif /* !RT_OS_WINDOWS */
4319
4320 /*
4321 * Snapshot folder:
4322 * Here we test only for a FAT partition as we had to create a dummy file otherwise
4323 */
4324 if ( enmFsTypeSnap == RTFSTYPE_FAT
4325 && i64Size >= _4G
4326 && !mfSnapshotFolderSizeWarningShown)
4327 {
4328 const char *pszUnit;
4329 uint64_t u64Print = formatDiskSize(i64Size, &pszUnit);
4330 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
4331#ifdef RT_OS_WINDOWS
4332 N_("The snapshot folder of this VM '%ls' seems to be located on "
4333 "a FAT(32) file system. The logical size of the medium '%ls' "
4334 "(%RU64%s) is bigger than the maximum file size this file "
4335 "system can handle (4GB).\n"
4336 "We strongly recommend to put all your virtual disk images and "
4337 "the snapshot folder onto an NTFS partition"),
4338#else
4339 N_("The snapshot folder of this VM '%ls' seems to be located on "
4340 "a FAT(32) file system. The logical size of the medium '%ls' "
4341 "(%RU64%s) is bigger than the maximum file size this file "
4342 "system can handle (4GB).\n"
4343 "We strongly recommend to put all your virtual disk images and "
4344 "the snapshot folder onto a proper file system (e.g. ext3)"),
4345#endif
4346 strSnap.raw(), strFile.raw(), u64Print, pszUnit);
4347 /* Show this particular warning only once */
4348 mfSnapshotFolderSizeWarningShown = true;
4349 }
4350
4351#ifdef RT_OS_LINUX
4352 /*
4353 * Ext4 bug: Check if the host I/O cache is disabled and the disk image is located
4354 * on an ext4 partition.
4355 * This bug apparently applies to the XFS file system as well.
4356 * Linux 2.6.36 is known to be fixed (tested with 2.6.36-rc4).
4357 */
4358
4359 char szOsRelease[128];
4360 int rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOsRelease, sizeof(szOsRelease));
4361 bool fKernelHasODirectBug = RT_FAILURE(rc)
4362 || (RTStrVersionCompare(szOsRelease, "2.6.36-rc4") < 0);
4363
4364 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
4365 && !*pfUseHostIOCache
4366 && fKernelHasODirectBug)
4367 {
4368 if ( enmFsTypeFile == RTFSTYPE_EXT4
4369 || enmFsTypeFile == RTFSTYPE_XFS)
4370 {
4371 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
4372 N_("The host I/O cache for at least one controller is disabled "
4373 "and the medium '%ls' for this VM "
4374 "is located on an %s partition. There is a known Linux "
4375 "kernel bug which can lead to the corruption of the virtual "
4376 "disk image under these conditions.\n"
4377 "Either enable the host I/O cache permanently in the VM "
4378 "settings or put the disk image and the snapshot folder "
4379 "onto a different file system.\n"
4380 "The host I/O cache will now be enabled for this medium"),
4381 strFile.raw(), enmFsTypeFile == RTFSTYPE_EXT4 ? "ext4" : "xfs");
4382 *pfUseHostIOCache = true;
4383 }
4384 else if ( ( enmFsTypeSnap == RTFSTYPE_EXT4
4385 || enmFsTypeSnap == RTFSTYPE_XFS)
4386 && !mfSnapshotFolderExt4WarningShown)
4387 {
4388 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
4389 N_("The host I/O cache for at least one controller is disabled "
4390 "and the snapshot folder for this VM "
4391 "is located on an %s partition. There is a known Linux "
4392 "kernel bug which can lead to the corruption of the virtual "
4393 "disk image under these conditions.\n"
4394 "Either enable the host I/O cache permanently in the VM "
4395 "settings or put the disk image and the snapshot folder "
4396 "onto a different file system.\n"
4397 "The host I/O cache will now be enabled for this medium"),
4398 enmFsTypeSnap == RTFSTYPE_EXT4 ? "ext4" : "xfs");
4399 *pfUseHostIOCache = true;
4400 mfSnapshotFolderExt4WarningShown = true;
4401 }
4402 }
4403
4404 /*
4405 * 2.6.18 bug: Check if the host I/O cache is disabled and the host is running
4406 * Linux 2.6.18. See @bugref{8690}. Apparently the same problem as
4407 * documented in https://lkml.org/lkml/2007/2/1/14. We saw such
4408 * kernel oopses on Linux 2.6.18-416.el5. We don't know when this
4409 * was fixed but we _know_ that 2.6.18 EL5 kernels are affected.
4410 */
4411 bool fKernelAsyncUnreliable = RT_FAILURE(rc)
4412 || (RTStrVersionCompare(szOsRelease, "2.6.19") < 0);
4413 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
4414 && !*pfUseHostIOCache
4415 && fKernelAsyncUnreliable)
4416 {
4417 i_atVMRuntimeErrorCallbackF(0, "Linux2618TooOld",
4418 N_("The host I/O cache for at least one controller is disabled. "
4419 "There is a known Linux kernel bug which can lead to kernel "
4420 "oopses under heavy load. To our knowledge this bug affects "
4421 "all 2.6.18 kernels.\n"
4422 "Either enable the host I/O cache permanently in the VM "
4423 "settings or switch to a newer host kernel.\n"
4424 "The host I/O cache will now be enabled for this medium"));
4425 *pfUseHostIOCache = true;
4426 }
4427#endif
4428 }
4429#undef H
4430
4431 return VINF_SUCCESS;
4432}
4433
4434/**
4435 * Unmounts the specified medium from the specified device.
4436 *
4437 * @returns VBox status code.
4438 * @param pUVM The usermode VM handle.
4439 * @param enmBus The storage bus.
4440 * @param enmDevType The device type.
4441 * @param pcszDevice The device emulation.
4442 * @param uInstance Instance of the device.
4443 * @param uLUN The LUN on the device.
4444 * @param fForceUnmount Whether to force unmounting.
4445 */
4446int Console::i_unmountMediumFromGuest(PUVM pUVM, StorageBus_T enmBus, DeviceType_T enmDevType,
4447 const char *pcszDevice, unsigned uInstance, unsigned uLUN,
4448 bool fForceUnmount)
4449{
4450 /* Unmount existing media only for floppy and DVD drives. */
4451 int rc = VINF_SUCCESS;
4452 PPDMIBASE pBase;
4453 if (enmBus == StorageBus_USB)
4454 rc = PDMR3UsbQueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
4455 else if ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI || enmBus == StorageBus_VirtioSCSI)
4456 || (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD))
4457 rc = PDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
4458 else /* IDE or Floppy */
4459 rc = PDMR3QueryLun(pUVM, pcszDevice, uInstance, uLUN, &pBase);
4460
4461 if (RT_FAILURE(rc))
4462 {
4463 if (rc == VERR_PDM_LUN_NOT_FOUND || rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4464 rc = VINF_SUCCESS;
4465 AssertRC(rc);
4466 }
4467 else
4468 {
4469 PPDMIMOUNT pIMount = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMOUNT);
4470 AssertReturn(pIMount, VERR_INVALID_POINTER);
4471
4472 /* Unmount the media (but do not eject the medium!) */
4473 rc = pIMount->pfnUnmount(pIMount, fForceUnmount, false /*=fEject*/);
4474 if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
4475 rc = VINF_SUCCESS;
4476 /* for example if the medium is locked */
4477 else if (RT_FAILURE(rc))
4478 return rc;
4479 }
4480
4481 return rc;
4482}
4483
4484/**
4485 * Removes the currently attached medium driver form the specified device
4486 * taking care of the controlelr specific configs wrt. to the attached driver chain.
4487 *
4488 * @returns VBox status code.
4489 * @param pCtlInst The controler instance node in the CFGM tree.
4490 * @param pcszDevice The device name.
4491 * @param uInstance The device instance.
4492 * @param uLUN The device LUN.
4493 * @param enmBus The storage bus.
4494 * @param fAttachDetach Flag whether this is a change while the VM is running
4495 * @param fHotplug Flag whether the guest should be notified about the device change.
4496 * @param fForceUnmount Flag whether to force unmounting the medium even if it is locked.
4497 * @param pUVM The usermode VM handle.
4498 * @param enmDevType The device type.
4499 * @param ppLunL0 Where to store the node to attach the new config to on success.
4500 */
4501int Console::i_removeMediumDriverFromVm(PCFGMNODE pCtlInst,
4502 const char *pcszDevice,
4503 unsigned uInstance,
4504 unsigned uLUN,
4505 StorageBus_T enmBus,
4506 bool fAttachDetach,
4507 bool fHotplug,
4508 bool fForceUnmount,
4509 PUVM pUVM,
4510 DeviceType_T enmDevType,
4511 PCFGMNODE *ppLunL0)
4512{
4513 int rc = VINF_SUCCESS;
4514 bool fAddLun = false;
4515
4516 /* First check if the LUN already exists. */
4517 PCFGMNODE pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
4518 AssertReturn(!VALID_PTR(pLunL0) || fAttachDetach, VERR_INTERNAL_ERROR);
4519
4520 if (pLunL0)
4521 {
4522 /*
4523 * Unmount the currently mounted medium if we don't just hot remove the
4524 * complete device (SATA) and it supports unmounting (DVD).
4525 */
4526 if ( (enmDevType != DeviceType_HardDisk)
4527 && !fHotplug)
4528 {
4529 rc = i_unmountMediumFromGuest(pUVM, enmBus, enmDevType, pcszDevice,
4530 uInstance, uLUN, fForceUnmount);
4531 if (RT_FAILURE(rc))
4532 return rc;
4533 }
4534
4535 /*
4536 * Don't detach the SCSI driver when unmounting the current medium
4537 * (we are not ripping out the device but only eject the medium).
4538 */
4539 char *pszDriverDetach = NULL;
4540 if ( !fHotplug
4541 && ( (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD)
4542 || enmBus == StorageBus_SAS
4543 || enmBus == StorageBus_SCSI
4544 || enmBus == StorageBus_VirtioSCSI
4545 || enmBus == StorageBus_USB))
4546 {
4547 /* Get the current attached driver we have to detach. */
4548 PCFGMNODE pDrvLun = CFGMR3GetChildF(pCtlInst, "LUN#%u/AttachedDriver/", uLUN);
4549 if (pDrvLun)
4550 {
4551 char szDriver[128];
4552 RT_ZERO(szDriver);
4553 rc = CFGMR3QueryString(pDrvLun, "Driver", &szDriver[0], sizeof(szDriver));
4554 if (RT_SUCCESS(rc))
4555 pszDriverDetach = RTStrDup(&szDriver[0]);
4556
4557 pLunL0 = pDrvLun;
4558 }
4559 }
4560
4561 if (enmBus == StorageBus_USB)
4562 rc = PDMR3UsbDriverDetach(pUVM, pcszDevice, uInstance, uLUN,
4563 pszDriverDetach, 0 /* iOccurence */,
4564 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
4565 else
4566 rc = PDMR3DriverDetach(pUVM, pcszDevice, uInstance, uLUN,
4567 pszDriverDetach, 0 /* iOccurence */,
4568 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
4569
4570 if (pszDriverDetach)
4571 {
4572 RTStrFree(pszDriverDetach);
4573 /* Remove the complete node and create new for the new config. */
4574 CFGMR3RemoveNode(pLunL0);
4575 pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
4576 if (pLunL0)
4577 {
4578 try
4579 {
4580 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4581 }
4582 catch (ConfigError &x)
4583 {
4584 // InsertConfig threw something:
4585 return x.m_vrc;
4586 }
4587 }
4588 }
4589 if (rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4590 rc = VINF_SUCCESS;
4591 AssertRCReturn(rc, rc);
4592
4593 /*
4594 * Don't remove the LUN except for IDE/floppy/NVMe (which connects directly to the medium driver
4595 * even for DVD devices) or if there is a hotplug event which rips out the complete device.
4596 */
4597 if ( fHotplug
4598 || enmBus == StorageBus_IDE
4599 || enmBus == StorageBus_Floppy
4600 || enmBus == StorageBus_PCIe
4601 || (enmBus == StorageBus_SATA && enmDevType != DeviceType_DVD))
4602 {
4603 fAddLun = true;
4604 CFGMR3RemoveNode(pLunL0);
4605 }
4606 }
4607 else
4608 fAddLun = true;
4609
4610 try
4611 {
4612 if (fAddLun)
4613 InsertConfigNode(pCtlInst, Utf8StrFmt("LUN#%u", uLUN).c_str(), &pLunL0);
4614 }
4615 catch (ConfigError &x)
4616 {
4617 // InsertConfig threw something:
4618 return x.m_vrc;
4619 }
4620
4621 if (ppLunL0)
4622 *ppLunL0 = pLunL0;
4623
4624 return rc;
4625}
4626
4627int Console::i_configMediumAttachment(const char *pcszDevice,
4628 unsigned uInstance,
4629 StorageBus_T enmBus,
4630 bool fUseHostIOCache,
4631 bool fBuiltinIOCache,
4632 bool fInsertDiskIntegrityDrv,
4633 bool fSetupMerge,
4634 unsigned uMergeSource,
4635 unsigned uMergeTarget,
4636 IMediumAttachment *pMediumAtt,
4637 MachineState_T aMachineState,
4638 HRESULT *phrc,
4639 bool fAttachDetach,
4640 bool fForceUnmount,
4641 bool fHotplug,
4642 PUVM pUVM,
4643 DeviceType_T *paLedDevType,
4644 PCFGMNODE *ppLunL0)
4645{
4646 // InsertConfig* throws
4647 try
4648 {
4649 int rc = VINF_SUCCESS;
4650 HRESULT hrc;
4651 Bstr bstr;
4652 PCFGMNODE pCtlInst = NULL;
4653
4654// #define RC_CHECK() AssertMsgReturn(RT_SUCCESS(rc), ("rc=%Rrc\n", rc), rc)
4655#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4656
4657 LONG lDev;
4658 hrc = pMediumAtt->COMGETTER(Device)(&lDev); H();
4659 LONG lPort;
4660 hrc = pMediumAtt->COMGETTER(Port)(&lPort); H();
4661 DeviceType_T lType;
4662 hrc = pMediumAtt->COMGETTER(Type)(&lType); H();
4663 BOOL fNonRotational;
4664 hrc = pMediumAtt->COMGETTER(NonRotational)(&fNonRotational); H();
4665 BOOL fDiscard;
4666 hrc = pMediumAtt->COMGETTER(Discard)(&fDiscard); H();
4667
4668 if (lType == DeviceType_DVD)
4669 fInsertDiskIntegrityDrv = false;
4670
4671 unsigned uLUN;
4672 PCFGMNODE pLunL0 = NULL;
4673 hrc = Console::i_storageBusPortDeviceToLun(enmBus, lPort, lDev, uLUN); H();
4674
4675 /* Determine the base path for the device instance. */
4676 if (enmBus != StorageBus_USB)
4677 pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "Devices/%s/%u/", pcszDevice, uInstance);
4678 else
4679 {
4680 /* If we hotplug a USB device create a new CFGM tree. */
4681 if (!fHotplug)
4682 pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "USB/%s/", pcszDevice);
4683 else
4684 pCtlInst = CFGMR3CreateTree(pUVM);
4685 }
4686 AssertReturn(pCtlInst, VERR_INTERNAL_ERROR);
4687
4688 if (enmBus == StorageBus_USB)
4689 {
4690 PCFGMNODE pCfg = NULL;
4691
4692 /* Create correct instance. */
4693 if (!fHotplug)
4694 {
4695 if (!fAttachDetach)
4696 InsertConfigNode(pCtlInst, Utf8StrFmt("%d", lPort).c_str(), &pCtlInst);
4697 else
4698 pCtlInst = CFGMR3GetChildF(pCtlInst, "%d/", lPort);
4699 }
4700
4701 if (!fAttachDetach)
4702 InsertConfigNode(pCtlInst, "Config", &pCfg);
4703
4704 uInstance = lPort; /* Overwrite uInstance with the correct one. */
4705
4706 if (!fHotplug && !fAttachDetach)
4707 {
4708 char aszUuid[RTUUID_STR_LENGTH + 1];
4709 USBStorageDevice UsbMsd = USBStorageDevice();
4710
4711 memset(aszUuid, 0, sizeof(aszUuid));
4712 rc = RTUuidCreate(&UsbMsd.mUuid);
4713 AssertRCReturn(rc, rc);
4714 rc = RTUuidToStr(&UsbMsd.mUuid, aszUuid, sizeof(aszUuid));
4715 AssertRCReturn(rc, rc);
4716
4717 UsbMsd.iPort = uInstance;
4718
4719 InsertConfigString(pCtlInst, "UUID", aszUuid);
4720 mUSBStorageDevices.push_back(UsbMsd);
4721
4722 /** @todo No LED after hotplugging. */
4723 /* Attach the status driver */
4724 i_attachStatusDriver(pCtlInst, DeviceType_HardDisk, 0, 7, &paLedDevType,
4725 &mapMediumAttachments, pcszDevice, 0);
4726 }
4727 }
4728
4729 rc = i_removeMediumDriverFromVm(pCtlInst, pcszDevice, uInstance, uLUN, enmBus, fAttachDetach,
4730 fHotplug, fForceUnmount, pUVM, lType, &pLunL0);
4731 if (RT_FAILURE(rc))
4732 return rc;
4733 if (ppLunL0)
4734 *ppLunL0 = pLunL0;
4735
4736 Utf8Str devicePath = Utf8StrFmt("%s/%u/LUN#%u", pcszDevice, uInstance, uLUN);
4737 mapMediumAttachments[devicePath] = pMediumAtt;
4738
4739 ComPtr<IMedium> ptrMedium;
4740 hrc = pMediumAtt->COMGETTER(Medium)(ptrMedium.asOutParam()); H();
4741
4742 /*
4743 * 1. Only check this for hard disk images.
4744 * 2. Only check during VM creation and not later, especially not during
4745 * taking an online snapshot!
4746 */
4747 if ( lType == DeviceType_HardDisk
4748 && ( aMachineState == MachineState_Starting
4749 || aMachineState == MachineState_Restoring))
4750 {
4751 rc = i_checkMediumLocation(ptrMedium, &fUseHostIOCache);
4752 if (RT_FAILURE(rc))
4753 return rc;
4754 }
4755
4756 BOOL fPassthrough = FALSE;
4757 if (ptrMedium.isNotNull())
4758 {
4759 BOOL fHostDrive;
4760 hrc = ptrMedium->COMGETTER(HostDrive)(&fHostDrive); H();
4761 if ( ( lType == DeviceType_DVD
4762 || lType == DeviceType_Floppy)
4763 && !fHostDrive)
4764 {
4765 /*
4766 * Informative logging.
4767 */
4768 Bstr strFile;
4769 hrc = ptrMedium->COMGETTER(Location)(strFile.asOutParam()); H();
4770 Utf8Str utfFile = Utf8Str(strFile);
4771 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
4772 (void)RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
4773 LogRel(("File system of '%s' (%s) is %s\n",
4774 utfFile.c_str(), lType == DeviceType_DVD ? "DVD" : "Floppy",
4775 RTFsTypeName(enmFsTypeFile)));
4776 }
4777
4778 if (fHostDrive)
4779 {
4780 hrc = pMediumAtt->COMGETTER(Passthrough)(&fPassthrough); H();
4781 }
4782 }
4783
4784 ComObjPtr<IBandwidthGroup> pBwGroup;
4785 Bstr strBwGroup;
4786 hrc = pMediumAtt->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
4787
4788 if (!pBwGroup.isNull())
4789 {
4790 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
4791 }
4792
4793 /*
4794 * Insert the SCSI driver for hotplug events on the SCSI/USB based storage controllers
4795 * or for SATA if the new device is a CD/DVD drive.
4796 */
4797 if ( (fHotplug || !fAttachDetach)
4798 && ( (enmBus == StorageBus_SCSI || enmBus == StorageBus_SAS || enmBus == StorageBus_USB || enmBus == StorageBus_VirtioSCSI)
4799 || (enmBus == StorageBus_SATA && lType == DeviceType_DVD && !fPassthrough)))
4800 {
4801 InsertConfigString(pLunL0, "Driver", "SCSI");
4802 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4803 }
4804
4805 rc = i_configMedium(pLunL0,
4806 !!fPassthrough,
4807 lType,
4808 fUseHostIOCache,
4809 fBuiltinIOCache,
4810 fInsertDiskIntegrityDrv,
4811 fSetupMerge,
4812 uMergeSource,
4813 uMergeTarget,
4814 strBwGroup.isEmpty() ? NULL : Utf8Str(strBwGroup).c_str(),
4815 !!fDiscard,
4816 !!fNonRotational,
4817 ptrMedium,
4818 aMachineState,
4819 phrc);
4820 if (RT_FAILURE(rc))
4821 return rc;
4822
4823 if (fAttachDetach)
4824 {
4825 /* Attach the new driver. */
4826 if (enmBus == StorageBus_USB)
4827 {
4828 if (fHotplug)
4829 {
4830 USBStorageDevice UsbMsd = USBStorageDevice();
4831 RTUuidCreate(&UsbMsd.mUuid);
4832 UsbMsd.iPort = uInstance;
4833 rc = PDMR3UsbCreateEmulatedDevice(pUVM, pcszDevice, pCtlInst, &UsbMsd.mUuid, NULL);
4834 if (RT_SUCCESS(rc))
4835 mUSBStorageDevices.push_back(UsbMsd);
4836 }
4837 else
4838 rc = PDMR3UsbDriverAttach(pUVM, pcszDevice, uInstance, uLUN,
4839 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4840 }
4841 else if ( !fHotplug
4842 && ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI || enmBus == StorageBus_VirtioSCSI)
4843 || (enmBus == StorageBus_SATA && lType == DeviceType_DVD)))
4844 rc = PDMR3DriverAttach(pUVM, pcszDevice, uInstance, uLUN,
4845 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4846 else
4847 rc = PDMR3DeviceAttach(pUVM, pcszDevice, uInstance, uLUN,
4848 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4849 AssertRCReturn(rc, rc);
4850
4851 /*
4852 * Make the secret key helper interface known to the VD driver if it is attached,
4853 * so we can get notified about missing keys.
4854 */
4855 PPDMIBASE pIBase = NULL;
4856 rc = PDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "VD", &pIBase);
4857 if (RT_SUCCESS(rc) && pIBase)
4858 {
4859 PPDMIMEDIA pIMedium = (PPDMIMEDIA)pIBase->pfnQueryInterface(pIBase, PDMIMEDIA_IID);
4860 if (pIMedium)
4861 {
4862 rc = pIMedium->pfnSetSecKeyIf(pIMedium, mpIfSecKey, mpIfSecKeyHlp);
4863 Assert(RT_SUCCESS(rc) || rc == VERR_NOT_SUPPORTED);
4864 }
4865 }
4866
4867 /* There is no need to handle removable medium mounting, as we
4868 * unconditionally replace everthing including the block driver level.
4869 * This means the new medium will be picked up automatically. */
4870 }
4871
4872 if (paLedDevType)
4873 paLedDevType[uLUN] = lType;
4874
4875 /* Dump the changed LUN if possible, dump the complete device otherwise */
4876 if ( aMachineState != MachineState_Starting
4877 && aMachineState != MachineState_Restoring)
4878 CFGMR3Dump(pLunL0 ? pLunL0 : pCtlInst);
4879 }
4880 catch (ConfigError &x)
4881 {
4882 // InsertConfig threw something:
4883 return x.m_vrc;
4884 }
4885
4886#undef H
4887
4888 return VINF_SUCCESS;
4889}
4890
4891int Console::i_configMedium(PCFGMNODE pLunL0,
4892 bool fPassthrough,
4893 DeviceType_T enmType,
4894 bool fUseHostIOCache,
4895 bool fBuiltinIOCache,
4896 bool fInsertDiskIntegrityDrv,
4897 bool fSetupMerge,
4898 unsigned uMergeSource,
4899 unsigned uMergeTarget,
4900 const char *pcszBwGroup,
4901 bool fDiscard,
4902 bool fNonRotational,
4903 ComPtr<IMedium> ptrMedium,
4904 MachineState_T aMachineState,
4905 HRESULT *phrc)
4906{
4907 // InsertConfig* throws
4908 try
4909 {
4910 HRESULT hrc;
4911 Bstr bstr;
4912 PCFGMNODE pCfg = NULL;
4913
4914#define H() \
4915 AssertMsgReturnStmt(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), if (phrc) *phrc = hrc, Global::vboxStatusCodeFromCOM(hrc))
4916
4917
4918 BOOL fHostDrive = FALSE;
4919 MediumType_T mediumType = MediumType_Normal;
4920 if (ptrMedium.isNotNull())
4921 {
4922 hrc = ptrMedium->COMGETTER(HostDrive)(&fHostDrive); H();
4923 hrc = ptrMedium->COMGETTER(Type)(&mediumType); H();
4924 }
4925
4926 if (fHostDrive)
4927 {
4928 Assert(ptrMedium.isNotNull());
4929 if (enmType == DeviceType_DVD)
4930 {
4931 InsertConfigString(pLunL0, "Driver", "HostDVD");
4932 InsertConfigNode(pLunL0, "Config", &pCfg);
4933
4934 hrc = ptrMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4935 InsertConfigString(pCfg, "Path", bstr);
4936
4937 InsertConfigInteger(pCfg, "Passthrough", fPassthrough);
4938 }
4939 else if (enmType == DeviceType_Floppy)
4940 {
4941 InsertConfigString(pLunL0, "Driver", "HostFloppy");
4942 InsertConfigNode(pLunL0, "Config", &pCfg);
4943
4944 hrc = ptrMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4945 InsertConfigString(pCfg, "Path", bstr);
4946 }
4947 }
4948 else
4949 {
4950 if (fInsertDiskIntegrityDrv)
4951 {
4952 /*
4953 * The actual configuration is done through CFGM extra data
4954 * for each inserted driver separately.
4955 */
4956 InsertConfigString(pLunL0, "Driver", "DiskIntegrity");
4957 InsertConfigNode(pLunL0, "Config", &pCfg);
4958 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4959 }
4960
4961 InsertConfigString(pLunL0, "Driver", "VD");
4962 InsertConfigNode(pLunL0, "Config", &pCfg);
4963 switch (enmType)
4964 {
4965 case DeviceType_DVD:
4966 InsertConfigString(pCfg, "Type", "DVD");
4967 InsertConfigInteger(pCfg, "Mountable", 1);
4968 break;
4969 case DeviceType_Floppy:
4970 InsertConfigString(pCfg, "Type", "Floppy 1.44");
4971 InsertConfigInteger(pCfg, "Mountable", 1);
4972 break;
4973 case DeviceType_HardDisk:
4974 default:
4975 InsertConfigString(pCfg, "Type", "HardDisk");
4976 InsertConfigInteger(pCfg, "Mountable", 0);
4977 }
4978
4979 if ( ptrMedium.isNotNull()
4980 && ( enmType == DeviceType_DVD
4981 || enmType == DeviceType_Floppy)
4982 )
4983 {
4984 // if this medium represents an ISO image and this image is inaccessible,
4985 // the ignore it instead of causing a failure; this can happen when we
4986 // restore a VM state and the ISO has disappeared, e.g. because the Guest
4987 // Additions were mounted and the user upgraded VirtualBox. Previously
4988 // we failed on startup, but that's not good because the only way out then
4989 // would be to discard the VM state...
4990 MediumState_T mediumState;
4991 hrc = ptrMedium->RefreshState(&mediumState); H();
4992 if (mediumState == MediumState_Inaccessible)
4993 {
4994 Bstr loc;
4995 hrc = ptrMedium->COMGETTER(Location)(loc.asOutParam()); H();
4996 i_atVMRuntimeErrorCallbackF(0, "DvdOrFloppyImageInaccessible",
4997 "The image file '%ls' is inaccessible and is being ignored. "
4998 "Please select a different image file for the virtual %s drive.",
4999 loc.raw(),
5000 enmType == DeviceType_DVD ? "DVD" : "floppy");
5001 ptrMedium.setNull();
5002 }
5003 }
5004
5005 if (ptrMedium.isNotNull())
5006 {
5007 /* Start with length of parent chain, as the list is reversed */
5008 unsigned uImage = 0;
5009 ComPtr<IMedium> ptrTmp = ptrMedium;
5010 while (ptrTmp.isNotNull())
5011 {
5012 uImage++;
5013 ComPtr<IMedium> ptrParent;
5014 hrc = ptrTmp->COMGETTER(Parent)(ptrParent.asOutParam()); H();
5015 ptrTmp = ptrParent;
5016 }
5017 /* Index of last image */
5018 uImage--;
5019
5020# ifdef VBOX_WITH_EXTPACK
5021 if (mptrExtPackManager->i_isExtPackUsable(ORACLE_PUEL_EXTPACK_NAME))
5022 {
5023 /* Configure loading the VDPlugin. */
5024 static const char s_szVDPlugin[] = "VDPluginCrypt";
5025 PCFGMNODE pCfgPlugins = NULL;
5026 PCFGMNODE pCfgPlugin = NULL;
5027 Utf8Str strPlugin;
5028 hrc = mptrExtPackManager->i_getLibraryPathForExtPack(s_szVDPlugin, ORACLE_PUEL_EXTPACK_NAME, &strPlugin);
5029 // Don't fail, this is optional!
5030 if (SUCCEEDED(hrc))
5031 {
5032 InsertConfigNode(pCfg, "Plugins", &pCfgPlugins);
5033 InsertConfigNode(pCfgPlugins, s_szVDPlugin, &pCfgPlugin);
5034 InsertConfigString(pCfgPlugin, "Path", strPlugin.c_str());
5035 }
5036 }
5037# endif
5038
5039 hrc = ptrMedium->COMGETTER(Location)(bstr.asOutParam()); H();
5040 InsertConfigString(pCfg, "Path", bstr);
5041
5042 hrc = ptrMedium->COMGETTER(Format)(bstr.asOutParam()); H();
5043 InsertConfigString(pCfg, "Format", bstr);
5044
5045 if (mediumType == MediumType_Readonly)
5046 InsertConfigInteger(pCfg, "ReadOnly", 1);
5047 else if (enmType == DeviceType_Floppy)
5048 InsertConfigInteger(pCfg, "MaybeReadOnly", 1);
5049
5050 /* Start without exclusive write access to the images. */
5051 /** @todo Live Migration: I don't quite like this, we risk screwing up when
5052 * we're resuming the VM if some 3rd dude have any of the VDIs open
5053 * with write sharing denied. However, if the two VMs are sharing a
5054 * image it really is necessary....
5055 *
5056 * So, on the "lock-media" command, the target teleporter should also
5057 * make DrvVD undo TempReadOnly. It gets interesting if we fail after
5058 * that. Grumble. */
5059 if ( enmType == DeviceType_HardDisk
5060 && aMachineState == MachineState_TeleportingIn)
5061 InsertConfigInteger(pCfg, "TempReadOnly", 1);
5062
5063 /* Flag for opening the medium for sharing between VMs. This
5064 * is done at the moment only for the first (and only) medium
5065 * in the chain, as shared media can have no diffs. */
5066 if (mediumType == MediumType_Shareable)
5067 InsertConfigInteger(pCfg, "Shareable", 1);
5068
5069 if (!fUseHostIOCache)
5070 {
5071 InsertConfigInteger(pCfg, "UseNewIo", 1);
5072 /*
5073 * Activate the builtin I/O cache for harddisks only.
5074 * It caches writes only which doesn't make sense for DVD drives
5075 * and just increases the overhead.
5076 */
5077 if ( fBuiltinIOCache
5078 && (enmType == DeviceType_HardDisk))
5079 InsertConfigInteger(pCfg, "BlockCache", 1);
5080 }
5081
5082 if (fSetupMerge)
5083 {
5084 InsertConfigInteger(pCfg, "SetupMerge", 1);
5085 if (uImage == uMergeSource)
5086 InsertConfigInteger(pCfg, "MergeSource", 1);
5087 else if (uImage == uMergeTarget)
5088 InsertConfigInteger(pCfg, "MergeTarget", 1);
5089 }
5090
5091 if (pcszBwGroup)
5092 InsertConfigString(pCfg, "BwGroup", pcszBwGroup);
5093
5094 if (fDiscard)
5095 InsertConfigInteger(pCfg, "Discard", 1);
5096
5097 if (fNonRotational)
5098 InsertConfigInteger(pCfg, "NonRotationalMedium", 1);
5099
5100 /* Pass all custom parameters. */
5101 bool fHostIP = true;
5102 bool fEncrypted = false;
5103 hrc = i_configMediumProperties(pCfg, ptrMedium, &fHostIP, &fEncrypted); H();
5104
5105 /* Create an inverted list of parents. */
5106 uImage--;
5107 ComPtr<IMedium> ptrParentMedium = ptrMedium;
5108 for (PCFGMNODE pParent = pCfg;; uImage--)
5109 {
5110 ComPtr<IMedium> ptrCurMedium;
5111 hrc = ptrParentMedium->COMGETTER(Parent)(ptrCurMedium.asOutParam()); H();
5112 if (ptrCurMedium.isNull())
5113 break;
5114
5115 PCFGMNODE pCur;
5116 InsertConfigNode(pParent, "Parent", &pCur);
5117 hrc = ptrCurMedium->COMGETTER(Location)(bstr.asOutParam()); H();
5118 InsertConfigString(pCur, "Path", bstr);
5119
5120 hrc = ptrCurMedium->COMGETTER(Format)(bstr.asOutParam()); H();
5121 InsertConfigString(pCur, "Format", bstr);
5122
5123 if (fSetupMerge)
5124 {
5125 if (uImage == uMergeSource)
5126 InsertConfigInteger(pCur, "MergeSource", 1);
5127 else if (uImage == uMergeTarget)
5128 InsertConfigInteger(pCur, "MergeTarget", 1);
5129 }
5130
5131 /* Configure medium properties. */
5132 hrc = i_configMediumProperties(pCur, ptrCurMedium, &fHostIP, &fEncrypted); H();
5133
5134 /* next */
5135 pParent = pCur;
5136 ptrParentMedium = ptrCurMedium;
5137 }
5138
5139 /* Custom code: put marker to not use host IP stack to driver
5140 * configuration node. Simplifies life of DrvVD a bit. */
5141 if (!fHostIP)
5142 InsertConfigInteger(pCfg, "HostIPStack", 0);
5143
5144 if (fEncrypted)
5145 m_cDisksEncrypted++;
5146 }
5147 else
5148 {
5149 /* Set empty drive flag for DVD or floppy without media. */
5150 if ( enmType == DeviceType_DVD
5151 || enmType == DeviceType_Floppy)
5152 InsertConfigInteger(pCfg, "EmptyDrive", 1);
5153 }
5154 }
5155#undef H
5156 }
5157 catch (ConfigError &x)
5158 {
5159 // InsertConfig threw something:
5160 return x.m_vrc;
5161 }
5162
5163 return VINF_SUCCESS;
5164}
5165
5166/**
5167 * Adds the medium properties to the CFGM tree.
5168 *
5169 * @returns VBox status code.
5170 * @param pCur The current CFGM node.
5171 * @param pMedium The medium object to configure.
5172 * @param pfHostIP Where to return the value of the \"HostIPStack\" property if found.
5173 * @param pfEncrypted Where to return whether the medium is encrypted.
5174 */
5175int Console::i_configMediumProperties(PCFGMNODE pCur, IMedium *pMedium, bool *pfHostIP, bool *pfEncrypted)
5176{
5177 /* Pass all custom parameters. */
5178 SafeArray<BSTR> aNames;
5179 SafeArray<BSTR> aValues;
5180 HRESULT hrc = pMedium->GetProperties(NULL, ComSafeArrayAsOutParam(aNames),
5181 ComSafeArrayAsOutParam(aValues));
5182
5183 if ( SUCCEEDED(hrc)
5184 && aNames.size() != 0)
5185 {
5186 PCFGMNODE pVDC;
5187 InsertConfigNode(pCur, "VDConfig", &pVDC);
5188 for (size_t ii = 0; ii < aNames.size(); ++ii)
5189 {
5190 if (aValues[ii] && *aValues[ii])
5191 {
5192 Utf8Str name = aNames[ii];
5193 Utf8Str value = aValues[ii];
5194 size_t offSlash = name.find("/", 0);
5195 if ( offSlash != name.npos
5196 && !name.startsWith("Special/"))
5197 {
5198 com::Utf8Str strFilter;
5199 com::Utf8Str strKey;
5200
5201 hrc = strFilter.assignEx(name, 0, offSlash);
5202 if (FAILED(hrc))
5203 break;
5204
5205 hrc = strKey.assignEx(name, offSlash + 1, name.length() - offSlash - 1); /* Skip slash */
5206 if (FAILED(hrc))
5207 break;
5208
5209 PCFGMNODE pCfgFilterConfig = CFGMR3GetChild(pVDC, strFilter.c_str());
5210 if (!pCfgFilterConfig)
5211 InsertConfigNode(pVDC, strFilter.c_str(), &pCfgFilterConfig);
5212
5213 InsertConfigString(pCfgFilterConfig, strKey.c_str(), value);
5214 }
5215 else
5216 {
5217 InsertConfigString(pVDC, name.c_str(), value);
5218 if ( name.compare("HostIPStack") == 0
5219 && value.compare("0") == 0)
5220 *pfHostIP = false;
5221 }
5222
5223 if ( name.compare("CRYPT/KeyId") == 0
5224 && pfEncrypted)
5225 *pfEncrypted = true;
5226 }
5227 }
5228 }
5229
5230 return hrc;
5231}
5232
5233
5234/**
5235 * Construct the Network configuration tree
5236 *
5237 * @returns VBox status code.
5238 *
5239 * @param pszDevice The PDM device name.
5240 * @param uInstance The PDM device instance.
5241 * @param uLun The PDM LUN number of the drive.
5242 * @param aNetworkAdapter The network adapter whose attachment needs to be changed
5243 * @param pCfg Configuration node for the device
5244 * @param pLunL0 To store the pointer to the LUN#0.
5245 * @param pInst The instance CFGM node
5246 * @param fAttachDetach To determine if the network attachment should
5247 * be attached/detached after/before
5248 * configuration.
5249 * @param fIgnoreConnectFailure
5250 * True if connection failures should be ignored
5251 * (makes only sense for bridged/host-only networks).
5252 *
5253 * @note Locks this object for writing.
5254 * @thread EMT
5255 */
5256int Console::i_configNetwork(const char *pszDevice,
5257 unsigned uInstance,
5258 unsigned uLun,
5259 INetworkAdapter *aNetworkAdapter,
5260 PCFGMNODE pCfg,
5261 PCFGMNODE pLunL0,
5262 PCFGMNODE pInst,
5263 bool fAttachDetach,
5264 bool fIgnoreConnectFailure)
5265{
5266 RT_NOREF(fIgnoreConnectFailure);
5267 AutoCaller autoCaller(this);
5268 AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED);
5269
5270 // InsertConfig* throws
5271 try
5272 {
5273 int rc = VINF_SUCCESS;
5274 HRESULT hrc;
5275 Bstr bstr;
5276
5277#ifdef VBOX_WITH_CLOUD_NET
5278 /* We'll need device's pCfg for cloud attachments */
5279 PCFGMNODE pDevCfg = pCfg;
5280#endif /* VBOX_WITH_CLOUD_NET */
5281
5282#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
5283
5284 /*
5285 * Locking the object before doing VMR3* calls is quite safe here, since
5286 * we're on EMT. Write lock is necessary because we indirectly modify the
5287 * meAttachmentType member.
5288 */
5289 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
5290
5291 ComPtr<IMachine> pMachine = i_machine();
5292
5293 ComPtr<IVirtualBox> virtualBox;
5294 hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam()); H();
5295
5296 ComPtr<IHost> host;
5297 hrc = virtualBox->COMGETTER(Host)(host.asOutParam()); H();
5298
5299 BOOL fSniffer;
5300 hrc = aNetworkAdapter->COMGETTER(TraceEnabled)(&fSniffer); H();
5301
5302 NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy;
5303 hrc = aNetworkAdapter->COMGETTER(PromiscModePolicy)(&enmPromiscModePolicy); H();
5304 const char *pszPromiscuousGuestPolicy;
5305 switch (enmPromiscModePolicy)
5306 {
5307 case NetworkAdapterPromiscModePolicy_Deny: pszPromiscuousGuestPolicy = "deny"; break;
5308 case NetworkAdapterPromiscModePolicy_AllowNetwork: pszPromiscuousGuestPolicy = "allow-network"; break;
5309 case NetworkAdapterPromiscModePolicy_AllowAll: pszPromiscuousGuestPolicy = "allow-all"; break;
5310 default: AssertFailedReturn(VERR_INTERNAL_ERROR_4);
5311 }
5312
5313 if (fAttachDetach)
5314 {
5315 rc = PDMR3DeviceDetach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/);
5316 if (rc == VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN)
5317 rc = VINF_SUCCESS;
5318 AssertLogRelRCReturn(rc, rc);
5319
5320 /* Nuke anything which might have been left behind. */
5321 CFGMR3RemoveNode(CFGMR3GetChildF(pInst, "LUN#%u", uLun));
5322 }
5323
5324 Bstr networkName, trunkName, trunkType;
5325 NetworkAttachmentType_T eAttachmentType;
5326 hrc = aNetworkAdapter->COMGETTER(AttachmentType)(&eAttachmentType); H();
5327
5328#ifdef VBOX_WITH_NETSHAPER
5329 ComObjPtr<IBandwidthGroup> pBwGroup;
5330 Bstr strBwGroup;
5331 hrc = aNetworkAdapter->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
5332
5333 if (!pBwGroup.isNull())
5334 {
5335 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
5336 }
5337#endif /* VBOX_WITH_NETSHAPER */
5338
5339 AssertMsg(uLun == 0, ("Network attachments with LUN > 0 are not supported yet\n"));
5340 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", uLun);
5341
5342 /*
5343 * Do not insert neither a shaper nor a sniffer if we are not attached to anything.
5344 * This way we can easily detect if we are attached to anything at the device level.
5345 */
5346#ifdef VBOX_WITH_NETSHAPER
5347 if (!strBwGroup.isEmpty() && eAttachmentType != NetworkAttachmentType_Null)
5348 {
5349 InsertConfigString(pLunL0, "Driver", "NetShaper");
5350 InsertConfigNode(pLunL0, "Config", &pCfg);
5351 InsertConfigString(pCfg, "BwGroup", strBwGroup);
5352 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
5353 }
5354#endif /* VBOX_WITH_NETSHAPER */
5355
5356 if (fSniffer && eAttachmentType != NetworkAttachmentType_Null)
5357 {
5358 InsertConfigString(pLunL0, "Driver", "NetSniffer");
5359 InsertConfigNode(pLunL0, "Config", &pCfg);
5360 hrc = aNetworkAdapter->COMGETTER(TraceFile)(bstr.asOutParam()); H();
5361 if (!bstr.isEmpty()) /* check convention for indicating default file. */
5362 InsertConfigString(pCfg, "File", bstr);
5363 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
5364 }
5365
5366 switch (eAttachmentType)
5367 {
5368 case NetworkAttachmentType_Null:
5369 break;
5370
5371 case NetworkAttachmentType_NAT:
5372 {
5373 ComPtr<INATEngine> natEngine;
5374 hrc = aNetworkAdapter->COMGETTER(NATEngine)(natEngine.asOutParam()); H();
5375 InsertConfigString(pLunL0, "Driver", "NAT");
5376 InsertConfigNode(pLunL0, "Config", &pCfg);
5377
5378 /* Configure TFTP prefix and boot filename. */
5379 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
5380 if (!bstr.isEmpty())
5381 InsertConfigString(pCfg, "TFTPPrefix", Utf8StrFmt("%ls%c%s", bstr.raw(), RTPATH_DELIMITER, "TFTP"));
5382 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
5383 InsertConfigString(pCfg, "BootFile", Utf8StrFmt("%ls.pxe", bstr.raw()));
5384
5385 hrc = natEngine->COMGETTER(Network)(bstr.asOutParam()); H();
5386 if (!bstr.isEmpty())
5387 InsertConfigString(pCfg, "Network", bstr);
5388 else
5389 {
5390 ULONG uSlot;
5391 hrc = aNetworkAdapter->COMGETTER(Slot)(&uSlot); H();
5392 InsertConfigString(pCfg, "Network", Utf8StrFmt("10.0.%d.0/24", uSlot+2));
5393 }
5394 hrc = natEngine->COMGETTER(HostIP)(bstr.asOutParam()); H();
5395 if (!bstr.isEmpty())
5396 InsertConfigString(pCfg, "BindIP", bstr);
5397 ULONG mtu = 0;
5398 ULONG sockSnd = 0;
5399 ULONG sockRcv = 0;
5400 ULONG tcpSnd = 0;
5401 ULONG tcpRcv = 0;
5402 hrc = natEngine->GetNetworkSettings(&mtu, &sockSnd, &sockRcv, &tcpSnd, &tcpRcv); H();
5403 if (mtu)
5404 InsertConfigInteger(pCfg, "SlirpMTU", mtu);
5405 if (sockRcv)
5406 InsertConfigInteger(pCfg, "SockRcv", sockRcv);
5407 if (sockSnd)
5408 InsertConfigInteger(pCfg, "SockSnd", sockSnd);
5409 if (tcpRcv)
5410 InsertConfigInteger(pCfg, "TcpRcv", tcpRcv);
5411 if (tcpSnd)
5412 InsertConfigInteger(pCfg, "TcpSnd", tcpSnd);
5413 hrc = natEngine->COMGETTER(TFTPPrefix)(bstr.asOutParam()); H();
5414 if (!bstr.isEmpty())
5415 {
5416 RemoveConfigValue(pCfg, "TFTPPrefix");
5417 InsertConfigString(pCfg, "TFTPPrefix", bstr);
5418 }
5419 hrc = natEngine->COMGETTER(TFTPBootFile)(bstr.asOutParam()); H();
5420 if (!bstr.isEmpty())
5421 {
5422 RemoveConfigValue(pCfg, "BootFile");
5423 InsertConfigString(pCfg, "BootFile", bstr);
5424 }
5425 hrc = natEngine->COMGETTER(TFTPNextServer)(bstr.asOutParam()); H();
5426 if (!bstr.isEmpty())
5427 InsertConfigString(pCfg, "NextServer", bstr);
5428 BOOL fDNSFlag;
5429 hrc = natEngine->COMGETTER(DNSPassDomain)(&fDNSFlag); H();
5430 InsertConfigInteger(pCfg, "PassDomain", fDNSFlag);
5431 hrc = natEngine->COMGETTER(DNSProxy)(&fDNSFlag); H();
5432 InsertConfigInteger(pCfg, "DNSProxy", fDNSFlag);
5433 hrc = natEngine->COMGETTER(DNSUseHostResolver)(&fDNSFlag); H();
5434 InsertConfigInteger(pCfg, "UseHostResolver", fDNSFlag);
5435
5436 ULONG aliasMode;
5437 hrc = natEngine->COMGETTER(AliasMode)(&aliasMode); H();
5438 InsertConfigInteger(pCfg, "AliasMode", aliasMode);
5439
5440 /* port-forwarding */
5441 SafeArray<BSTR> pfs;
5442 hrc = natEngine->COMGETTER(Redirects)(ComSafeArrayAsOutParam(pfs)); H();
5443
5444 PCFGMNODE pPFTree = NULL;
5445 if (pfs.size() > 0)
5446 InsertConfigNode(pCfg, "PortForwarding", &pPFTree);
5447
5448 for (unsigned int i = 0; i < pfs.size(); ++i)
5449 {
5450 PCFGMNODE pPF = NULL; /* /Devices/Dev/.../Config/PortForwarding/$n/ */
5451
5452 uint16_t port = 0;
5453 Utf8Str utf = pfs[i];
5454 Utf8Str strName;
5455 Utf8Str strProto;
5456 Utf8Str strHostPort;
5457 Utf8Str strHostIP;
5458 Utf8Str strGuestPort;
5459 Utf8Str strGuestIP;
5460 size_t pos, ppos;
5461 pos = ppos = 0;
5462#define ITERATE_TO_NEXT_TERM(res, str, pos, ppos) \
5463 { \
5464 pos = str.find(",", ppos); \
5465 if (pos == Utf8Str::npos) \
5466 { \
5467 Log(( #res " extracting from %s is failed\n", str.c_str())); \
5468 continue; \
5469 } \
5470 res = str.substr(ppos, pos - ppos); \
5471 Log2((#res " %s pos:%d, ppos:%d\n", res.c_str(), pos, ppos)); \
5472 ppos = pos + 1; \
5473 } /* no do { ... } while because of 'continue' */
5474 ITERATE_TO_NEXT_TERM(strName, utf, pos, ppos);
5475 ITERATE_TO_NEXT_TERM(strProto, utf, pos, ppos);
5476 ITERATE_TO_NEXT_TERM(strHostIP, utf, pos, ppos);
5477 ITERATE_TO_NEXT_TERM(strHostPort, utf, pos, ppos);
5478 ITERATE_TO_NEXT_TERM(strGuestIP, utf, pos, ppos);
5479 strGuestPort = utf.substr(ppos, utf.length() - ppos);
5480#undef ITERATE_TO_NEXT_TERM
5481
5482 uint32_t proto = strProto.toUInt32();
5483 bool fValid = true;
5484 switch (proto)
5485 {
5486 case NATProtocol_UDP:
5487 strProto = "UDP";
5488 break;
5489 case NATProtocol_TCP:
5490 strProto = "TCP";
5491 break;
5492 default:
5493 fValid = false;
5494 }
5495 /* continue with next rule if no valid proto was passed */
5496 if (!fValid)
5497 continue;
5498
5499 InsertConfigNode(pPFTree, Utf8StrFmt("%u", i).c_str(), &pPF);
5500
5501 if (!strName.isEmpty())
5502 InsertConfigString(pPF, "Name", strName);
5503
5504 InsertConfigString(pPF, "Protocol", strProto);
5505
5506 if (!strHostIP.isEmpty())
5507 InsertConfigString(pPF, "BindIP", strHostIP);
5508
5509 if (!strGuestIP.isEmpty())
5510 InsertConfigString(pPF, "GuestIP", strGuestIP);
5511
5512 port = RTStrToUInt16(strHostPort.c_str());
5513 if (port)
5514 InsertConfigInteger(pPF, "HostPort", port);
5515
5516 port = RTStrToUInt16(strGuestPort.c_str());
5517 if (port)
5518 InsertConfigInteger(pPF, "GuestPort", port);
5519 }
5520 break;
5521 }
5522
5523 case NetworkAttachmentType_Bridged:
5524 {
5525#if (defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)) && !defined(VBOX_WITH_NETFLT)
5526 hrc = i_attachToTapInterface(aNetworkAdapter);
5527 if (FAILED(hrc))
5528 {
5529 switch (hrc)
5530 {
5531 case VERR_ACCESS_DENIED:
5532 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5533 "Failed to open '/dev/net/tun' for read/write access. Please check the "
5534 "permissions of that node. Either run 'chmod 0666 /dev/net/tun' or "
5535 "change the group of that node and make yourself a member of that group. Make "
5536 "sure that these changes are permanent, especially if you are "
5537 "using udev"));
5538 default:
5539 AssertMsgFailed(("Could not attach to host interface! Bad!\n"));
5540 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5541 "Failed to initialize Host Interface Networking"));
5542 }
5543 }
5544
5545 Assert((intptr_t)maTapFD[uInstance] >= 0);
5546 if ((intptr_t)maTapFD[uInstance] >= 0)
5547 {
5548 InsertConfigString(pLunL0, "Driver", "HostInterface");
5549 InsertConfigNode(pLunL0, "Config", &pCfg);
5550 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
5551 }
5552
5553#elif defined(VBOX_WITH_NETFLT)
5554 /*
5555 * This is the new VBoxNetFlt+IntNet stuff.
5556 */
5557 Bstr BridgedIfName;
5558 hrc = aNetworkAdapter->COMGETTER(BridgedInterface)(BridgedIfName.asOutParam());
5559 if (FAILED(hrc))
5560 {
5561 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(BridgedInterface) failed, hrc (0x%x)\n", hrc));
5562 H();
5563 }
5564
5565 Utf8Str BridgedIfNameUtf8(BridgedIfName);
5566 const char *pszBridgedIfName = BridgedIfNameUtf8.c_str();
5567
5568 ComPtr<IHostNetworkInterface> hostInterface;
5569 hrc = host->FindHostNetworkInterfaceByName(BridgedIfName.raw(),
5570 hostInterface.asOutParam());
5571 if (!SUCCEEDED(hrc))
5572 {
5573 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: FindByName failed, rc=%Rhrc (0x%x)\n", hrc, hrc));
5574 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5575 N_("Nonexistent host networking interface, name '%ls'"),
5576 BridgedIfName.raw());
5577 }
5578
5579# if defined(RT_OS_DARWIN)
5580 /* The name is on the form 'ifX: long name', chop it off at the colon. */
5581 char szTrunk[INTNET_MAX_TRUNK_NAME];
5582 RTStrCopy(szTrunk, sizeof(szTrunk), pszBridgedIfName);
5583 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
5584// Quick fix for @bugref{5633}
5585// if (!pszColon)
5586// {
5587// /*
5588// * Dynamic changing of attachment causes an attempt to configure
5589// * network with invalid host adapter (as it is must be changed before
5590// * the attachment), calling Detach here will cause a deadlock.
5591// * See @bugref{4750}.
5592// * hrc = aNetworkAdapter->Detach(); H();
5593// */
5594// return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5595// N_("Malformed host interface networking name '%ls'"),
5596// BridgedIfName.raw());
5597// }
5598 if (pszColon)
5599 *pszColon = '\0';
5600 const char *pszTrunk = szTrunk;
5601
5602# elif defined(RT_OS_SOLARIS)
5603 /* The name is on the form format 'ifX[:1] - long name, chop it off at space. */
5604 char szTrunk[256];
5605 strlcpy(szTrunk, pszBridgedIfName, sizeof(szTrunk));
5606 char *pszSpace = (char *)memchr(szTrunk, ' ', sizeof(szTrunk));
5607
5608 /*
5609 * Currently don't bother about malformed names here for the sake of people using
5610 * VBoxManage and setting only the NIC name from there. If there is a space we
5611 * chop it off and proceed, otherwise just use whatever we've got.
5612 */
5613 if (pszSpace)
5614 *pszSpace = '\0';
5615
5616 /* Chop it off at the colon (zone naming eg: e1000g:1 we need only the e1000g) */
5617 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
5618 if (pszColon)
5619 *pszColon = '\0';
5620
5621 const char *pszTrunk = szTrunk;
5622
5623# elif defined(RT_OS_WINDOWS)
5624 HostNetworkInterfaceType_T eIfType;
5625 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
5626 if (FAILED(hrc))
5627 {
5628 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
5629 H();
5630 }
5631
5632 if (eIfType != HostNetworkInterfaceType_Bridged)
5633 {
5634 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5635 N_("Interface ('%ls') is not a Bridged Adapter interface"),
5636 BridgedIfName.raw());
5637 }
5638
5639 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
5640 if (FAILED(hrc))
5641 {
5642 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
5643 H();
5644 }
5645 Guid hostIFGuid(bstr);
5646
5647 INetCfg *pNc;
5648 ComPtr<INetCfgComponent> pAdaptorComponent;
5649 LPWSTR pszApp;
5650
5651 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
5652 Assert(hrc == S_OK);
5653 if (hrc != S_OK)
5654 {
5655 LogRel(("NetworkAttachmentType_Bridged: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5656 H();
5657 }
5658
5659 /* get the adapter's INetCfgComponent*/
5660 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
5661 pAdaptorComponent.asOutParam());
5662 if (hrc != S_OK)
5663 {
5664 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5665 LogRel(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)\n", hrc));
5666 H();
5667 }
5668# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
5669 char szTrunkName[INTNET_MAX_TRUNK_NAME];
5670 char *pszTrunkName = szTrunkName;
5671 wchar_t * pswzBindName;
5672 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
5673 Assert(hrc == S_OK);
5674 if (hrc == S_OK)
5675 {
5676 int cwBindName = (int)wcslen(pswzBindName) + 1;
5677 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
5678 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
5679 {
5680 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
5681 pszTrunkName += cbFullBindNamePrefix-1;
5682 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
5683 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
5684 {
5685 DWORD err = GetLastError();
5686 hrc = HRESULT_FROM_WIN32(err);
5687 AssertMsgFailed(("hrc=%Rhrc %#x\n", hrc, hrc));
5688 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
5689 hrc, hrc, err));
5690 }
5691 }
5692 else
5693 {
5694 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: insufficient szTrunkName buffer space\n"));
5695 /** @todo set appropriate error code */
5696 hrc = E_FAIL;
5697 }
5698
5699 if (hrc != S_OK)
5700 {
5701 AssertFailed();
5702 CoTaskMemFree(pswzBindName);
5703 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5704 H();
5705 }
5706
5707 /* we're not freeing the bind name since we'll use it later for detecting wireless*/
5708 }
5709 else
5710 {
5711 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5712 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)",
5713 hrc));
5714 H();
5715 }
5716
5717 const char *pszTrunk = szTrunkName;
5718 /* we're not releasing the INetCfg stuff here since we use it later to figure out whether it is wireless */
5719
5720# elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
5721# if defined(RT_OS_FREEBSD)
5722 /*
5723 * If we bridge to a tap interface open it the `old' direct way.
5724 * This works and performs better than bridging a physical
5725 * interface via the current FreeBSD vboxnetflt implementation.
5726 */
5727 if (!strncmp(pszBridgedIfName, RT_STR_TUPLE("tap"))) {
5728 hrc = i_attachToTapInterface(aNetworkAdapter);
5729 if (FAILED(hrc))
5730 {
5731 switch (hrc)
5732 {
5733 case E_ACCESSDENIED:
5734 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5735 "Failed to open '/dev/%s' for read/write access. Please check the "
5736 "permissions of that node, and that the net.link.tap.user_open "
5737 "sysctl is set. Either run 'chmod 0666 /dev/%s' or "
5738 "change the group of that node to vboxusers and make yourself "
5739 "a member of that group. Make sure that these changes are permanent."),
5740 pszBridgedIfName, pszBridgedIfName);
5741 default:
5742 AssertMsgFailed(("Could not attach to tap interface! Bad!\n"));
5743 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5744 "Failed to initialize Host Interface Networking"));
5745 }
5746 }
5747
5748 Assert((intptr_t)maTapFD[uInstance] >= 0);
5749 if ((intptr_t)maTapFD[uInstance] >= 0)
5750 {
5751 InsertConfigString(pLunL0, "Driver", "HostInterface");
5752 InsertConfigNode(pLunL0, "Config", &pCfg);
5753 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
5754 }
5755 break;
5756 }
5757# endif
5758 /** @todo Check for malformed names. */
5759 const char *pszTrunk = pszBridgedIfName;
5760
5761 /* Issue a warning if the interface is down */
5762 {
5763 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
5764 if (iSock >= 0)
5765 {
5766 struct ifreq Req;
5767 RT_ZERO(Req);
5768 RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pszBridgedIfName);
5769 if (ioctl(iSock, SIOCGIFFLAGS, &Req) >= 0)
5770 if ((Req.ifr_flags & IFF_UP) == 0)
5771 i_atVMRuntimeErrorCallbackF(0, "BridgedInterfaceDown",
5772 N_("Bridged interface %s is down. Guest will not be able to use this interface"),
5773 pszBridgedIfName);
5774
5775 close(iSock);
5776 }
5777 }
5778
5779# else
5780# error "PORTME (VBOX_WITH_NETFLT)"
5781# endif
5782
5783 InsertConfigString(pLunL0, "Driver", "IntNet");
5784 InsertConfigNode(pLunL0, "Config", &pCfg);
5785 InsertConfigString(pCfg, "Trunk", pszTrunk);
5786 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
5787 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure);
5788 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5789 char szNetwork[INTNET_MAX_NETWORK_NAME];
5790
5791# if defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN)
5792 /*
5793 * 'pszTrunk' contains just the interface name required in ring-0, while 'pszBridgedIfName' contains
5794 * interface name + optional description. We must not pass any description to the VM as it can differ
5795 * for the same interface name, eg: "nge0 - ethernet" (GUI) vs "nge0" (VBoxManage).
5796 */
5797 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszTrunk);
5798# else
5799 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszBridgedIfName);
5800# endif
5801 InsertConfigString(pCfg, "Network", szNetwork);
5802 networkName = Bstr(szNetwork);
5803 trunkName = Bstr(pszTrunk);
5804 trunkType = Bstr(TRUNKTYPE_NETFLT);
5805
5806 BOOL fSharedMacOnWire = false;
5807 hrc = hostInterface->COMGETTER(Wireless)(&fSharedMacOnWire);
5808 if (FAILED(hrc))
5809 {
5810 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Wireless) failed, hrc (0x%x)\n", hrc));
5811 H();
5812 }
5813 else if (fSharedMacOnWire)
5814 {
5815 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5816 Log(("Set SharedMacOnWire\n"));
5817 }
5818
5819# if defined(RT_OS_SOLARIS)
5820# if 0 /* bird: this is a bit questionable and might cause more trouble than its worth. */
5821 /* Zone access restriction, don't allow snooping the global zone. */
5822 zoneid_t ZoneId = getzoneid();
5823 if (ZoneId != GLOBAL_ZONEID)
5824 {
5825 InsertConfigInteger(pCfg, "IgnoreAllPromisc", true);
5826 }
5827# endif
5828# endif
5829
5830#elif defined(RT_OS_WINDOWS) /* not defined NetFlt */
5831 /* NOTHING TO DO HERE */
5832#elif defined(RT_OS_LINUX)
5833/// @todo aleksey: is there anything to be done here?
5834#elif defined(RT_OS_FREEBSD)
5835/** @todo FreeBSD: Check out this later (HIF networking). */
5836#else
5837# error "Port me"
5838#endif
5839 break;
5840 }
5841
5842 case NetworkAttachmentType_Internal:
5843 {
5844 hrc = aNetworkAdapter->COMGETTER(InternalNetwork)(bstr.asOutParam()); H();
5845 if (!bstr.isEmpty())
5846 {
5847 InsertConfigString(pLunL0, "Driver", "IntNet");
5848 InsertConfigNode(pLunL0, "Config", &pCfg);
5849 InsertConfigString(pCfg, "Network", bstr);
5850 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
5851 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5852 networkName = bstr;
5853 trunkType = Bstr(TRUNKTYPE_WHATEVER);
5854 }
5855 break;
5856 }
5857
5858 case NetworkAttachmentType_HostOnly:
5859 {
5860 InsertConfigString(pLunL0, "Driver", "IntNet");
5861 InsertConfigNode(pLunL0, "Config", &pCfg);
5862
5863 Bstr HostOnlyName;
5864 hrc = aNetworkAdapter->COMGETTER(HostOnlyInterface)(HostOnlyName.asOutParam());
5865 if (FAILED(hrc))
5866 {
5867 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(HostOnlyInterface) failed, hrc (0x%x)\n", hrc));
5868 H();
5869 }
5870
5871 Utf8Str HostOnlyNameUtf8(HostOnlyName);
5872 const char *pszHostOnlyName = HostOnlyNameUtf8.c_str();
5873 ComPtr<IHostNetworkInterface> hostInterface;
5874 rc = host->FindHostNetworkInterfaceByName(HostOnlyName.raw(),
5875 hostInterface.asOutParam());
5876 if (!SUCCEEDED(rc))
5877 {
5878 LogRel(("NetworkAttachmentType_HostOnly: FindByName failed, rc (0x%x)\n", rc));
5879 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5880 N_("Nonexistent host networking interface, name '%ls'"),
5881 HostOnlyName.raw());
5882 }
5883
5884 char szNetwork[INTNET_MAX_NETWORK_NAME];
5885 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszHostOnlyName);
5886
5887#if defined(RT_OS_WINDOWS)
5888# ifndef VBOX_WITH_NETFLT
5889 hrc = E_NOTIMPL;
5890 LogRel(("NetworkAttachmentType_HostOnly: Not Implemented\n"));
5891 H();
5892# else /* defined VBOX_WITH_NETFLT*/
5893 /** @todo r=bird: Put this in a function. */
5894
5895 HostNetworkInterfaceType_T eIfType;
5896 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
5897 if (FAILED(hrc))
5898 {
5899 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
5900 H();
5901 }
5902
5903 if (eIfType != HostNetworkInterfaceType_HostOnly)
5904 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5905 N_("Interface ('%ls') is not a Host-Only Adapter interface"),
5906 HostOnlyName.raw());
5907
5908 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
5909 if (FAILED(hrc))
5910 {
5911 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
5912 H();
5913 }
5914 Guid hostIFGuid(bstr);
5915
5916 INetCfg *pNc;
5917 ComPtr<INetCfgComponent> pAdaptorComponent;
5918 LPWSTR pszApp;
5919 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
5920 Assert(hrc == S_OK);
5921 if (hrc != S_OK)
5922 {
5923 LogRel(("NetworkAttachmentType_HostOnly: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5924 H();
5925 }
5926
5927 /* get the adapter's INetCfgComponent*/
5928 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
5929 pAdaptorComponent.asOutParam());
5930 if (hrc != S_OK)
5931 {
5932 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5933 LogRel(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5934 H();
5935 }
5936# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
5937 char szTrunkName[INTNET_MAX_TRUNK_NAME];
5938 bool fNdis6 = false;
5939 wchar_t * pwszHelpText;
5940 hrc = pAdaptorComponent->GetHelpText(&pwszHelpText);
5941 Assert(hrc == S_OK);
5942 if (hrc == S_OK)
5943 {
5944 Log(("help-text=%ls\n", pwszHelpText));
5945 if (!wcscmp(pwszHelpText, L"VirtualBox NDIS 6.0 Miniport Driver"))
5946 fNdis6 = true;
5947 CoTaskMemFree(pwszHelpText);
5948 }
5949 if (fNdis6)
5950 {
5951 strncpy(szTrunkName, pszHostOnlyName, sizeof(szTrunkName) - 1);
5952 Log(("trunk=%s\n", szTrunkName));
5953 }
5954 else
5955 {
5956 char *pszTrunkName = szTrunkName;
5957 wchar_t * pswzBindName;
5958 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
5959 Assert(hrc == S_OK);
5960 if (hrc == S_OK)
5961 {
5962 int cwBindName = (int)wcslen(pswzBindName) + 1;
5963 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
5964 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
5965 {
5966 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
5967 pszTrunkName += cbFullBindNamePrefix-1;
5968 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
5969 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
5970 {
5971 DWORD err = GetLastError();
5972 hrc = HRESULT_FROM_WIN32(err);
5973 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
5974 hrc, hrc, err));
5975 }
5976 }
5977 else
5978 {
5979 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: insufficient szTrunkName buffer space\n"));
5980 /** @todo set appropriate error code */
5981 hrc = E_FAIL;
5982 }
5983
5984 if (hrc != S_OK)
5985 {
5986 AssertFailed();
5987 CoTaskMemFree(pswzBindName);
5988 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5989 H();
5990 }
5991 }
5992 else
5993 {
5994 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5995 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n",
5996 hrc, hrc));
5997 H();
5998 }
5999
6000
6001 CoTaskMemFree(pswzBindName);
6002 }
6003
6004 trunkType = TRUNKTYPE_NETADP;
6005 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
6006
6007 pAdaptorComponent.setNull();
6008 /* release the pNc finally */
6009 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
6010
6011 const char *pszTrunk = szTrunkName;
6012
6013 InsertConfigString(pCfg, "Trunk", pszTrunk);
6014 InsertConfigString(pCfg, "Network", szNetwork);
6015 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure); /** @todo why is this
6016 windows only?? */
6017 networkName = Bstr(szNetwork);
6018 trunkName = Bstr(pszTrunk);
6019# endif /* defined VBOX_WITH_NETFLT*/
6020#elif defined(RT_OS_DARWIN)
6021 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
6022 InsertConfigString(pCfg, "Network", szNetwork);
6023 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
6024 networkName = Bstr(szNetwork);
6025 trunkName = Bstr(pszHostOnlyName);
6026 trunkType = TRUNKTYPE_NETADP;
6027#else
6028 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
6029 InsertConfigString(pCfg, "Network", szNetwork);
6030 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
6031 networkName = Bstr(szNetwork);
6032 trunkName = Bstr(pszHostOnlyName);
6033 trunkType = TRUNKTYPE_NETFLT;
6034#endif
6035 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
6036
6037#if !defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
6038
6039 Bstr tmpAddr, tmpMask;
6040
6041 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPAddress",
6042 pszHostOnlyName).raw(),
6043 tmpAddr.asOutParam());
6044 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty())
6045 {
6046 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPNetMask",
6047 pszHostOnlyName).raw(),
6048 tmpMask.asOutParam());
6049 if (SUCCEEDED(hrc) && !tmpMask.isEmpty())
6050 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
6051 tmpMask.raw());
6052 else
6053 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
6054 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
6055 }
6056 else
6057 {
6058 /* Grab the IP number from the 'vboxnetX' instance number (see netif.h) */
6059 hrc = hostInterface->EnableStaticIPConfig(getDefaultIPv4Address(Bstr(pszHostOnlyName)).raw(),
6060 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
6061 }
6062
6063 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
6064
6065 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6Address",
6066 pszHostOnlyName).raw(),
6067 tmpAddr.asOutParam());
6068 if (SUCCEEDED(hrc))
6069 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6NetMask", pszHostOnlyName).raw(),
6070 tmpMask.asOutParam());
6071 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty() && !tmpMask.isEmpty())
6072 {
6073 hrc = hostInterface->EnableStaticIPConfigV6(tmpAddr.raw(),
6074 Utf8Str(tmpMask).toUInt32());
6075 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
6076 }
6077#endif
6078 break;
6079 }
6080
6081 case NetworkAttachmentType_Generic:
6082 {
6083 hrc = aNetworkAdapter->COMGETTER(GenericDriver)(bstr.asOutParam()); H();
6084 SafeArray<BSTR> names;
6085 SafeArray<BSTR> values;
6086 hrc = aNetworkAdapter->GetProperties(Bstr().raw(),
6087 ComSafeArrayAsOutParam(names),
6088 ComSafeArrayAsOutParam(values)); H();
6089
6090 InsertConfigString(pLunL0, "Driver", bstr);
6091 InsertConfigNode(pLunL0, "Config", &pCfg);
6092 for (size_t ii = 0; ii < names.size(); ++ii)
6093 {
6094 if (values[ii] && *values[ii])
6095 {
6096 Utf8Str name = names[ii];
6097 Utf8Str value = values[ii];
6098 InsertConfigString(pCfg, name.c_str(), value);
6099 }
6100 }
6101 break;
6102 }
6103
6104 case NetworkAttachmentType_NATNetwork:
6105 {
6106 hrc = aNetworkAdapter->COMGETTER(NATNetwork)(bstr.asOutParam()); H();
6107 if (!bstr.isEmpty())
6108 {
6109 /** @todo add intnet prefix to separate namespaces, and add trunk if dealing with vboxnatX */
6110 InsertConfigString(pLunL0, "Driver", "IntNet");
6111 InsertConfigNode(pLunL0, "Config", &pCfg);
6112 InsertConfigString(pCfg, "Network", bstr);
6113 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
6114 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
6115 networkName = bstr;
6116 trunkType = Bstr(TRUNKTYPE_WHATEVER);
6117 }
6118 break;
6119 }
6120
6121#ifdef VBOX_WITH_CLOUD_NET
6122 case NetworkAttachmentType_Cloud:
6123 {
6124 static const char *s_pszCloudExtPackName = "Oracle VM VirtualBox Extension Pack";
6125 /*
6126 * Cloud network attachments do not work wihout installed extpack.
6127 * Without extpack support they won't work either.
6128 */
6129# ifdef VBOX_WITH_EXTPACK
6130 if (!mptrExtPackManager->i_isExtPackUsable(s_pszCloudExtPackName))
6131# endif
6132 {
6133 return VMSetError(VMR3GetVM(mpUVM), VERR_NOT_FOUND, RT_SRC_POS,
6134 N_("Implementation of the cloud network attachment not found!\n"
6135 "To fix this problem, either install the '%s' or switch to "
6136 "another network attachment type in the VM settings.\n"
6137 ),
6138 s_pszCloudExtPackName);
6139 }
6140
6141 ComPtr<ICloudNetwork> network;
6142 hrc = aNetworkAdapter->COMGETTER(CloudNetwork)(bstr.asOutParam()); H();
6143 hrc = pMachine->COMGETTER(Name)(mGateways.mTargetVM.asOutParam()); H();
6144 hrc = virtualBox->FindCloudNetworkByName(bstr.raw(), network.asOutParam()); H();
6145 hrc = startGateways(virtualBox, network, mGateways); H();
6146 InsertConfigBytes(pDevCfg, "MAC", &mGateways.mCloudMacAddress, sizeof(mGateways.mCloudMacAddress));
6147 if (!bstr.isEmpty())
6148 {
6149 InsertConfigString(pLunL0, "Driver", "IntNet");
6150 InsertConfigNode(pLunL0, "Config", &pCfg);
6151 InsertConfigString(pCfg, "Network", BstrFmt("cloud-%ls", bstr.raw()));
6152 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
6153 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
6154 networkName = bstr;
6155 trunkType = Bstr(TRUNKTYPE_WHATEVER);
6156 }
6157 break;
6158 }
6159#endif /* VBOX_WITH_CLOUD_NET */
6160
6161 default:
6162 AssertMsgFailed(("should not get here!\n"));
6163 break;
6164 }
6165
6166 /*
6167 * Attempt to attach the driver.
6168 */
6169 switch (eAttachmentType)
6170 {
6171 case NetworkAttachmentType_Null:
6172 break;
6173
6174 case NetworkAttachmentType_Bridged:
6175 case NetworkAttachmentType_Internal:
6176 case NetworkAttachmentType_HostOnly:
6177 case NetworkAttachmentType_NAT:
6178 case NetworkAttachmentType_Generic:
6179 case NetworkAttachmentType_NATNetwork:
6180#ifdef VBOX_WITH_CLOUD_NET
6181 case NetworkAttachmentType_Cloud:
6182#endif /* VBOX_WITH_CLOUD_NET */
6183 {
6184 if (SUCCEEDED(hrc) && RT_SUCCESS(rc))
6185 {
6186 if (fAttachDetach)
6187 {
6188 rc = PDMR3DriverAttach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/, NULL /* ppBase */);
6189 //AssertRC(rc);
6190 }
6191
6192 {
6193 /** @todo pritesh: get the dhcp server name from the
6194 * previous network configuration and then stop the server
6195 * else it may conflict with the dhcp server running with
6196 * the current attachment type
6197 */
6198 /* Stop the hostonly DHCP Server */
6199 }
6200
6201 /*
6202 * NAT networks start their DHCP server theirself, see NATNetwork::Start()
6203 */
6204 if ( !networkName.isEmpty()
6205 && eAttachmentType != NetworkAttachmentType_NATNetwork)
6206 {
6207 /*
6208 * Until we implement service reference counters DHCP Server will be stopped
6209 * by DHCPServerRunner destructor.
6210 */
6211 ComPtr<IDHCPServer> dhcpServer;
6212 hrc = virtualBox->FindDHCPServerByNetworkName(networkName.raw(),
6213 dhcpServer.asOutParam());
6214 if (SUCCEEDED(hrc))
6215 {
6216 /* there is a DHCP server available for this network */
6217 BOOL fEnabledDhcp;
6218 hrc = dhcpServer->COMGETTER(Enabled)(&fEnabledDhcp);
6219 if (FAILED(hrc))
6220 {
6221 LogRel(("DHCP svr: COMGETTER(Enabled) failed, hrc (%Rhrc)\n", hrc));
6222 H();
6223 }
6224
6225 if (fEnabledDhcp)
6226 hrc = dhcpServer->Start(trunkName.raw(),
6227 trunkType.raw());
6228 }
6229 else
6230 hrc = S_OK;
6231 }
6232 }
6233
6234 break;
6235 }
6236
6237 default:
6238 AssertMsgFailed(("should not get here!\n"));
6239 break;
6240 }
6241
6242 meAttachmentType[uInstance] = eAttachmentType;
6243 }
6244 catch (ConfigError &x)
6245 {
6246 // InsertConfig threw something:
6247 return x.m_vrc;
6248 }
6249
6250#undef H
6251
6252 return VINF_SUCCESS;
6253}
6254
6255
6256/**
6257 * Configures the serial port at the given CFGM node with the supplied parameters.
6258 *
6259 * @returns VBox status code.
6260 * @param pInst The instance CFGM node.
6261 * @param ePortMode The port mode to sue.
6262 * @param pszPath The serial port path.
6263 * @param fServer Flag whether the port should act as a server
6264 * for the pipe and TCP mode or connect as a client.
6265 */
6266int Console::i_configSerialPort(PCFGMNODE pInst, PortMode_T ePortMode, const char *pszPath, bool fServer)
6267{
6268 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
6269 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */
6270 PCFGMNODE pLunL1Cfg = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/Config */
6271
6272 try
6273 {
6274 InsertConfigNode(pInst, "LUN#0", &pLunL0);
6275 if (ePortMode == PortMode_HostPipe)
6276 {
6277 InsertConfigString(pLunL0, "Driver", "Char");
6278 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
6279 InsertConfigString(pLunL1, "Driver", "NamedPipe");
6280 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
6281 InsertConfigString(pLunL1Cfg, "Location", pszPath);
6282 InsertConfigInteger(pLunL1Cfg, "IsServer", fServer);
6283 }
6284 else if (ePortMode == PortMode_HostDevice)
6285 {
6286 InsertConfigString(pLunL0, "Driver", "Host Serial");
6287 InsertConfigNode(pLunL0, "Config", &pLunL1);
6288 InsertConfigString(pLunL1, "DevicePath", pszPath);
6289 }
6290 else if (ePortMode == PortMode_TCP)
6291 {
6292 InsertConfigString(pLunL0, "Driver", "Char");
6293 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
6294 InsertConfigString(pLunL1, "Driver", "TCP");
6295 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
6296 InsertConfigString(pLunL1Cfg, "Location", pszPath);
6297 InsertConfigInteger(pLunL1Cfg, "IsServer", fServer);
6298 }
6299 else if (ePortMode == PortMode_RawFile)
6300 {
6301 InsertConfigString(pLunL0, "Driver", "Char");
6302 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
6303 InsertConfigString(pLunL1, "Driver", "RawFile");
6304 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
6305 InsertConfigString(pLunL1Cfg, "Location", pszPath);
6306 }
6307 }
6308 catch (ConfigError &x)
6309 {
6310 /* InsertConfig threw something */
6311 return x.m_vrc;
6312 }
6313
6314 return VINF_SUCCESS;
6315}
6316
Note: See TracBrowser for help on using the repository browser.

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