VirtualBox

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

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

Main/ConsoleImpl2: Cleaned up i_configAudioDriver(). bugref:9890

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

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