VirtualBox

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

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

VMM,Main,HostServices: Use a function table for accessing the VBoxVMM.dll/so/dylib functionality, and load it dynamically when the Console object is initialized. Also converted a few drivers in Main to use device helpers to get config values and such. bugref:10074

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

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