VirtualBox

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

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

Main/ConsoleImpl: Modified the LED set enmType to a bitmap containing all possible types, thus allowing us to skip scanning the paSubTypes array when present. Also simplified i_attachStatusDriver a little. bugref:9892

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