VirtualBox

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

Last change on this file since 94974 was 94974, checked in by vboxsync, 3 years ago

GCM: Enabled divide by zero fixing automagic for some guests.

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

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