VirtualBox

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

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

Main/{MouseImpl,KeyboardImpl,ConsoleImpl): Drop passing pointers through CFGM in favor of using VMM2USERMETHODS::pfnQueryGenericObject, bugref:10053

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