VirtualBox

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

Last change on this file since 98091 was 98091, checked in by vboxsync, 2 years ago

Main/Console: LED related cleanups. bugref:9892

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