VirtualBox

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

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

libs/libssh,Main,FE/VBoxManage,Devices/Network/DrvCloudTunnel|ai: Add support for proxies, bugref:9469

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

© 2023 Oracle
ContactPrivacy policyTerms of Use