VirtualBox

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

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

Network: Do not bring up links for "not attached" adapters.

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