VirtualBox

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

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

Main/ConsoleImpl2: Log VBoxInternal/ overrides too. bugref:9890

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