VirtualBox

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

Last change on this file since 88369 was 88343, checked in by vboxsync, 4 years ago

Intel IOMMU: bugref:9967 Main: Fix typo which always disabled AMD IOMMU.

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