VirtualBox

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

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

VMM/HMSVM,ConsoleImpl2: Implemented an AMD-V workaround for missing TLB flush when OS/2 returns to protected mode from real mode. ticketref:20625

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

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