VirtualBox

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

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

Audio/HDA+AC97: Made the device emulation's internal [in|out]put FIFO buffer size configurable via extra data "VBoxInternal2/Audio/Device/BufSize[In|Out]Ms" (optional, defaults to 1000ms if not set). ticketoem2ref:36

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 259.9 KB
Line 
1/* $Id: ConsoleImpl2.cpp 87436 2021-01-26 16:59:29Z 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
3055 uint64_t uTmp;
3056 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/Device/PosAdjustEnabled", &strTmp);
3057 if (strTmp.isNotEmpty())
3058 {
3059 uTmp = strTmp.toUInt64(); /* Returns 0 if not set / invalid -> means disabled. */
3060 InsertConfigInteger(pCfg, "PosAdjustEnabled", uTmp);
3061 }
3062
3063 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/Device/PosAdjustFrames", &strTmp);
3064 if (strTmp.isNotEmpty())
3065 {
3066 uTmp = strTmp.toUInt64(); /* Ditto. */
3067 InsertConfigInteger(pCfg, "PosAdjustFrames", uTmp);
3068 }
3069
3070 break;
3071 }
3072 default:
3073 pszAudioDevice = "oops";
3074 AssertFailedBreak();
3075 }
3076
3077 PCFGMNODE pCfgAudioAdapter = NULL;
3078 InsertConfigNode(pInst, "AudioConfig", &pCfgAudioAdapter);
3079 SafeArray<BSTR> audioProps;
3080 hrc = audioAdapter->COMGETTER(PropertiesList)(ComSafeArrayAsOutParam(audioProps)); H();
3081
3082 std::list<Utf8Str> audioPropertyNamesList;
3083 for (size_t i = 0; i < audioProps.size(); ++i)
3084 {
3085 Bstr bstrValue;
3086 audioPropertyNamesList.push_back(Utf8Str(audioProps[i]));
3087 hrc = audioAdapter->GetProperty(audioProps[i], bstrValue.asOutParam());
3088 Utf8Str strKey(audioProps[i]);
3089 InsertConfigString(pCfgAudioAdapter, strKey.c_str(), bstrValue);
3090 }
3091
3092 /*
3093 * The audio driver.
3094 */
3095 AudioDriverType_T enmAudioDriver;
3096 hrc = audioAdapter->COMGETTER(AudioDriver)(&enmAudioDriver); H();
3097 const char *pszAudioDriver;
3098 switch (enmAudioDriver)
3099 {
3100 case AudioDriverType_Null:
3101 pszAudioDriver = "NullAudio";
3102 break;
3103#ifdef RT_OS_WINDOWS
3104# ifdef VBOX_WITH_WINMM
3105 case AudioDriverType_WinMM:
3106# error "Port WinMM audio backend!" /** @todo Still needed? */
3107 break;
3108# endif
3109 case AudioDriverType_DirectSound:
3110 pszAudioDriver = "DSoundAudio";
3111 break;
3112#endif /* RT_OS_WINDOWS */
3113#ifdef RT_OS_SOLARIS
3114 case AudioDriverType_SolAudio:
3115 /* Should not happen, as the Solaris Audio backend is not around anymore.
3116 * Remove this sometime later. */
3117 LogRel(("Audio: WARNING: Solaris Audio is deprecated, please switch to OSS!\n"));
3118 LogRel(("Audio: Automatically setting host audio backend to OSS\n"));
3119
3120 /* Manually set backend to OSS for now. */
3121 pszAudioDriver = "OSSAudio";
3122 break;
3123#endif
3124#ifdef VBOX_WITH_AUDIO_OSS
3125 case AudioDriverType_OSS:
3126 pszAudioDriver = "OSSAudio";
3127 break;
3128#endif
3129#ifdef VBOX_WITH_AUDIO_ALSA
3130 case AudioDriverType_ALSA:
3131 pszAudioDriver = "ALSAAudio";
3132 break;
3133#endif
3134#ifdef VBOX_WITH_AUDIO_PULSE
3135 case AudioDriverType_Pulse:
3136 pszAudioDriver = "PulseAudio";
3137 break;
3138#endif
3139#ifdef RT_OS_DARWIN
3140 case AudioDriverType_CoreAudio:
3141 pszAudioDriver = "CoreAudio";
3142 break;
3143#endif
3144 default:
3145 pszAudioDriver = "oops";
3146 AssertFailedBreak();
3147 }
3148
3149 unsigned uAudioLUN = 0;
3150
3151 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", uAudioLUN);
3152 rc = i_configAudioDriver(audioAdapter, virtualBox, pMachine, pLunL0, pszAudioDriver);
3153 if (RT_SUCCESS(rc))
3154 uAudioLUN++;
3155
3156#ifdef VBOX_WITH_AUDIO_VRDE
3157 /* Insert dummy audio driver to have the LUN configured. */
3158 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", uAudioLUN);
3159 InsertConfigString(pLunL0, "Driver", "AUDIO");
3160 AudioDriverCfg DrvCfgVRDE(pszAudioDevice, 0 /* Instance */, uAudioLUN, "AudioVRDE");
3161 rc = mAudioVRDE->InitializeConfig(&DrvCfgVRDE);
3162 if (RT_SUCCESS(rc))
3163 uAudioLUN++;
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", uAudioLUN);
3169 InsertConfigString(pLunL0, "Driver", "AUDIO");
3170 AudioDriverCfg DrvCfgVideoRec(pszAudioDevice, 0 /* Instance */, uAudioLUN, "AudioVideoRec");
3171 rc = Recording.mAudioRec->InitializeConfig(&DrvCfgVideoRec);
3172 if (RT_SUCCESS(rc))
3173 uAudioLUN++;
3174#endif /* VBOX_WITH_AUDIO_RECORDING */
3175
3176 if (fDebugEnabled)
3177 {
3178#ifdef VBOX_WITH_AUDIO_DEBUG
3179 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", uAudioLUN);
3180 rc = i_configAudioDriver(audioAdapter, virtualBox, pMachine, pLunL0, "DebugAudio");
3181 if (RT_SUCCESS(rc))
3182 uAudioLUN++;
3183#endif /* VBOX_WITH_AUDIO_DEBUG */
3184
3185 /*
3186 * Tweak the logging groups.
3187 */
3188 rc = RTLogGroupSettings(RTLogRelGetDefaultInstance(),
3189 "drv_host_audio.e.l.l2.l3.f"
3190 " drv_audio.e.l.l2.l3.f"
3191 " audio_mixer.e.l.l2.l3.f"
3192 " dev_hda_codec.e.l.l2.l3.f"
3193 " dev_hda.e.l.l2.l3.f"
3194 " dev_ac97.e.l.l2.l3.f"
3195 " dev_sb16.e.l.l2.l3.f");
3196 if (RT_FAILURE(rc))
3197 LogRel(("Audio: Setting debug logging failed, rc=%Rrc\n", rc));
3198 }
3199
3200#ifdef VBOX_WITH_AUDIO_VALIDATIONKIT
3201 /** @todo Make this a runtime-configurable entry! */
3202
3203 /*
3204 * The ValidationKit backend.
3205 */
3206 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", uAudioLUN);
3207 rc = i_configAudioDriver(audioAdapter, virtualBox, pMachine, pLunL0, "ValidationKitAudio");
3208 if (RT_SUCCESS(rc))
3209 uAudioLUN++;
3210#endif /* VBOX_WITH_AUDIO_VALIDATIONKIT */
3211 }
3212
3213#ifdef VBOX_WITH_SHARED_CLIPBOARD
3214 /*
3215 * Shared Clipboard.
3216 */
3217 {
3218 ClipboardMode_T enmClipboardMode = ClipboardMode_Disabled;
3219 hrc = pMachine->COMGETTER(ClipboardMode)(&enmClipboardMode); H();
3220# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
3221 BOOL fFileTransfersEnabled;
3222 hrc = pMachine->COMGETTER(ClipboardFileTransfersEnabled)(&fFileTransfersEnabled); H();
3223#endif
3224
3225 /* Load the service */
3226 rc = pVMMDev->hgcmLoadService("VBoxSharedClipboard", "VBoxSharedClipboard");
3227 if (RT_SUCCESS(rc))
3228 {
3229 LogRel(("Shared Clipboard: Service loaded\n"));
3230
3231 /* Set initial clipboard mode. */
3232 rc = i_changeClipboardMode(enmClipboardMode);
3233 AssertLogRelMsg(RT_SUCCESS(rc), ("Shared Clipboard: Failed to set initial clipboard mode (%d): rc=%Rrc\n",
3234 enmClipboardMode, rc));
3235
3236 /* Setup the service. */
3237 VBOXHGCMSVCPARM parm;
3238 HGCMSvcSetU32(&parm, !i_useHostClipboard());
3239 rc = pVMMDev->hgcmHostCall("VBoxSharedClipboard", VBOX_SHCL_HOST_FN_SET_HEADLESS, 1, &parm);
3240 AssertLogRelMsg(RT_SUCCESS(rc), ("Shared Clipboard: Failed to set initial headless mode (%RTbool): rc=%Rrc\n",
3241 !i_useHostClipboard(), rc));
3242
3243# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
3244 rc = i_changeClipboardFileTransferMode(RT_BOOL(fFileTransfersEnabled));
3245 AssertLogRelMsg(RT_SUCCESS(rc), ("Shared Clipboard: Failed to set initial file transfers mode (%u): rc=%Rrc\n",
3246 fFileTransfersEnabled, rc));
3247
3248 /** @todo Register area callbacks? (See also deregistration todo in Console::i_powerDown.) */
3249# endif
3250 }
3251 else
3252 LogRel(("Shared Clipboard: Not available, rc=%Rrc\n", rc));
3253 rc = VINF_SUCCESS; /* None of the potential failures above are fatal. */
3254 }
3255#endif /* VBOX_WITH_SHARED_CLIPBOARD */
3256
3257 /*
3258 * HGCM HostChannel.
3259 */
3260 {
3261 Bstr value;
3262 hrc = pMachine->GetExtraData(Bstr("HGCM/HostChannel").raw(),
3263 value.asOutParam());
3264
3265 if ( hrc == S_OK
3266 && value == "1")
3267 {
3268 rc = pVMMDev->hgcmLoadService("VBoxHostChannel", "VBoxHostChannel");
3269 if (RT_FAILURE(rc))
3270 {
3271 LogRel(("VBoxHostChannel is not available, rc=%Rrc\n", rc));
3272 /* That is not a fatal failure. */
3273 rc = VINF_SUCCESS;
3274 }
3275 }
3276 }
3277
3278#ifdef VBOX_WITH_DRAG_AND_DROP
3279 /*
3280 * Drag and Drop.
3281 */
3282 {
3283 DnDMode_T enmMode = DnDMode_Disabled;
3284 hrc = pMachine->COMGETTER(DnDMode)(&enmMode); H();
3285
3286 /* Load the service */
3287 rc = pVMMDev->hgcmLoadService("VBoxDragAndDropSvc", "VBoxDragAndDropSvc");
3288 if (RT_FAILURE(rc))
3289 {
3290 LogRel(("Drag and drop service is not available, rc=%Rrc\n", rc));
3291 /* That is not a fatal failure. */
3292 rc = VINF_SUCCESS;
3293 }
3294 else
3295 {
3296 rc = HGCMHostRegisterServiceExtension(&m_hHgcmSvcExtDragAndDrop, "VBoxDragAndDropSvc",
3297 &GuestDnD::notifyDnDDispatcher,
3298 GuestDnDInst());
3299 if (RT_FAILURE(rc))
3300 Log(("Cannot register VBoxDragAndDropSvc extension, rc=%Rrc\n", rc));
3301 else
3302 {
3303 LogRel(("Drag and drop service loaded\n"));
3304 rc = i_changeDnDMode(enmMode);
3305 }
3306 }
3307 }
3308#endif /* VBOX_WITH_DRAG_AND_DROP */
3309
3310 /*
3311 * ACPI
3312 */
3313 BOOL fACPI;
3314 hrc = biosSettings->COMGETTER(ACPIEnabled)(&fACPI); H();
3315 if (fACPI)
3316 {
3317 /* Always show the CPU leafs when we have multiple VCPUs or when the IO-APIC is enabled.
3318 * The Windows SMP kernel needs a CPU leaf or else its idle loop will burn cpu cycles; the
3319 * intelppm driver refuses to register an idle state handler.
3320 * Always show CPU leafs for OS X guests. */
3321 BOOL fShowCpu = fOsXGuest;
3322 if (cCpus > 1 || fIOAPIC)
3323 fShowCpu = true;
3324
3325 BOOL fCpuHotPlug;
3326 hrc = pMachine->COMGETTER(CPUHotPlugEnabled)(&fCpuHotPlug); H();
3327
3328 InsertConfigNode(pDevices, "acpi", &pDev);
3329 InsertConfigNode(pDev, "0", &pInst);
3330 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3331 InsertConfigNode(pInst, "Config", &pCfg);
3332 hrc = pBusMgr->assignPCIDevice("acpi", pInst); H();
3333
3334 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
3335
3336 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
3337 InsertConfigInteger(pCfg, "FdcEnabled", fFdcEnabled);
3338 InsertConfigInteger(pCfg, "HpetEnabled", fHPETEnabled);
3339 InsertConfigInteger(pCfg, "SmcEnabled", fSmcEnabled);
3340 InsertConfigInteger(pCfg, "ShowRtc", fShowRtc);
3341 if (fOsXGuest && !llBootNics.empty())
3342 {
3343 BootNic aNic = llBootNics.front();
3344 uint32_t u32NicPCIAddr = (aNic.mPCIAddress.miDevice << 16) | aNic.mPCIAddress.miFn;
3345 InsertConfigInteger(pCfg, "NicPciAddress", u32NicPCIAddr);
3346 }
3347 if (fOsXGuest && fAudioEnabled)
3348 {
3349 PCIBusAddress Address;
3350 if (pBusMgr->findPCIAddress("hda", 0, Address))
3351 {
3352 uint32_t u32AudioPCIAddr = (Address.miDevice << 16) | Address.miFn;
3353 InsertConfigInteger(pCfg, "AudioPciAddress", u32AudioPCIAddr);
3354 }
3355 }
3356 if (fOsXGuest)
3357 {
3358 PCIBusAddress Address;
3359 if (pBusMgr->findPCIAddress("nvme", 0, Address))
3360 {
3361 uint32_t u32NvmePCIAddr = (Address.miDevice << 16) | Address.miFn;
3362 InsertConfigInteger(pCfg, "NvmePciAddress", u32NvmePCIAddr);
3363 }
3364 }
3365#ifdef VBOX_WITH_IOMMU_AMD
3366 if (iommuType == IommuType_AMD)
3367 {
3368 PCIBusAddress Address;
3369 if (pBusMgr->findPCIAddress("iommu-amd", 0, Address))
3370 {
3371 uint32_t u32IommuAddress = (Address.miDevice << 16) | Address.miFn;
3372 InsertConfigInteger(pCfg, "IommuAmdEnabled", true);
3373 InsertConfigInteger(pCfg, "IommuAmdPciAddress", u32IommuAddress);
3374 if (pBusMgr->findPCIAddress("sb-ioapic", 0, Address))
3375 {
3376 uint32_t u32SbIoapicAddress = (Address.miDevice << 16) | Address.miFn;
3377 InsertConfigInteger(pCfg, "SbIoApicPciAddress", u32SbIoapicAddress);
3378 }
3379 else
3380 LogRel(("IOMMU: AMD IOMMU is enabled, but southbridge I/O APIC is not assigned a PCI address!\n"));
3381 }
3382 }
3383#endif
3384 InsertConfigInteger(pCfg, "IocPciAddress", uIocPCIAddress);
3385 if (chipsetType == ChipsetType_ICH9)
3386 {
3387 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
3388 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
3389 /* 64-bit prefetch window root resource:
3390 * Only for ICH9 and if PAE or Long Mode is enabled.
3391 * And only with hardware virtualization (@bugref{5454}). */
3392 if ( (fEnablePAE || fIsGuest64Bit)
3393 && fSupportsHwVirtEx /* HwVirt needs to be supported by the host
3394 otherwise VMM falls back to raw mode */
3395 && fHMEnabled /* HwVirt needs to be enabled in VM config */)
3396 InsertConfigInteger(pCfg, "PciPref64Enabled", 1);
3397 }
3398 InsertConfigInteger(pCfg, "HostBusPciAddress", uHbcPCIAddress);
3399 InsertConfigInteger(pCfg, "ShowCpu", fShowCpu);
3400 InsertConfigInteger(pCfg, "CpuHotPlug", fCpuHotPlug);
3401
3402 InsertConfigInteger(pCfg, "Serial0IoPortBase", auSerialIoPortBase[0]);
3403 InsertConfigInteger(pCfg, "Serial0Irq", auSerialIrq[0]);
3404
3405 InsertConfigInteger(pCfg, "Serial1IoPortBase", auSerialIoPortBase[1]);
3406 InsertConfigInteger(pCfg, "Serial1Irq", auSerialIrq[1]);
3407
3408 if (auSerialIoPortBase[2])
3409 {
3410 InsertConfigInteger(pCfg, "Serial2IoPortBase", auSerialIoPortBase[2]);
3411 InsertConfigInteger(pCfg, "Serial2Irq", auSerialIrq[2]);
3412 }
3413
3414 if (auSerialIoPortBase[3])
3415 {
3416 InsertConfigInteger(pCfg, "Serial3IoPortBase", auSerialIoPortBase[3]);
3417 InsertConfigInteger(pCfg, "Serial3Irq", auSerialIrq[3]);
3418 }
3419
3420 InsertConfigInteger(pCfg, "Parallel0IoPortBase", auParallelIoPortBase[0]);
3421 InsertConfigInteger(pCfg, "Parallel0Irq", auParallelIrq[0]);
3422
3423 InsertConfigInteger(pCfg, "Parallel1IoPortBase", auParallelIoPortBase[1]);
3424 InsertConfigInteger(pCfg, "Parallel1Irq", auParallelIrq[1]);
3425
3426 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3427 InsertConfigString(pLunL0, "Driver", "ACPIHost");
3428 InsertConfigNode(pLunL0, "Config", &pCfg);
3429
3430 /* Attach the dummy CPU drivers */
3431 for (ULONG iCpuCurr = 1; iCpuCurr < cCpus; iCpuCurr++)
3432 {
3433 BOOL fCpuAttached = true;
3434
3435 if (fCpuHotPlug)
3436 {
3437 hrc = pMachine->GetCPUStatus(iCpuCurr, &fCpuAttached); H();
3438 }
3439
3440 if (fCpuAttached)
3441 {
3442 InsertConfigNode(pInst, Utf8StrFmt("LUN#%u", iCpuCurr).c_str(), &pLunL0);
3443 InsertConfigString(pLunL0, "Driver", "ACPICpu");
3444 InsertConfigNode(pLunL0, "Config", &pCfg);
3445 }
3446 }
3447 }
3448
3449 /*
3450 * Configure DBGF (Debug(ger) Facility) and DBGC (Debugger Console).
3451 */
3452 {
3453 PCFGMNODE pDbgf;
3454 InsertConfigNode(pRoot, "DBGF", &pDbgf);
3455
3456 /* Paths to search for debug info and such things. */
3457 hrc = pMachine->COMGETTER(SettingsFilePath)(bstr.asOutParam()); H();
3458 Utf8Str strSettingsPath(bstr);
3459 bstr.setNull();
3460 strSettingsPath.stripFilename();
3461 strSettingsPath.append("/");
3462
3463 char szHomeDir[RTPATH_MAX + 1];
3464 int rc2 = RTPathUserHome(szHomeDir, sizeof(szHomeDir) - 1);
3465 if (RT_FAILURE(rc2))
3466 szHomeDir[0] = '\0';
3467 RTPathEnsureTrailingSeparator(szHomeDir, sizeof(szHomeDir));
3468
3469
3470 Utf8Str strPath;
3471 strPath.append(strSettingsPath).append("debug/;");
3472 strPath.append(strSettingsPath).append(";");
3473 strPath.append("cache*").append(strSettingsPath).append("dbgcache/;"); /* handy for symlinking to actual cache */
3474 strPath.append(szHomeDir);
3475
3476 InsertConfigString(pDbgf, "Path", strPath.c_str());
3477
3478 /* Tracing configuration. */
3479 BOOL fTracingEnabled;
3480 hrc = pMachine->COMGETTER(TracingEnabled)(&fTracingEnabled); H();
3481 if (fTracingEnabled)
3482 InsertConfigInteger(pDbgf, "TracingEnabled", 1);
3483
3484 hrc = pMachine->COMGETTER(TracingConfig)(bstr.asOutParam()); H();
3485 if (fTracingEnabled)
3486 InsertConfigString(pDbgf, "TracingConfig", bstr);
3487
3488 BOOL fAllowTracingToAccessVM;
3489 hrc = pMachine->COMGETTER(AllowTracingToAccessVM)(&fAllowTracingToAccessVM); H();
3490 if (fAllowTracingToAccessVM)
3491 InsertConfigInteger(pPDM, "AllowTracingToAccessVM", 1);
3492
3493 /* Debugger console config. */
3494 PCFGMNODE pDbgc;
3495 InsertConfigNode(pRoot, "DBGC", &pDbgc);
3496
3497 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
3498 Utf8Str strVBoxHome = bstr;
3499 bstr.setNull();
3500 if (strVBoxHome.isNotEmpty())
3501 strVBoxHome.append("/");
3502 else
3503 {
3504 strVBoxHome = szHomeDir;
3505 strVBoxHome.append("/.vbox");
3506 }
3507
3508 Utf8Str strFile(strVBoxHome);
3509 strFile.append("dbgc-history");
3510 InsertConfigString(pDbgc, "HistoryFile", strFile);
3511
3512 strFile = strSettingsPath;
3513 strFile.append("dbgc-init");
3514 InsertConfigString(pDbgc, "LocalInitScript", strFile);
3515
3516 strFile = strVBoxHome;
3517 strFile.append("dbgc-init");
3518 InsertConfigString(pDbgc, "GlobalInitScript", strFile);
3519 }
3520 }
3521 catch (ConfigError &x)
3522 {
3523 // InsertConfig threw something:
3524 return x.m_vrc;
3525 }
3526 catch (HRESULT hrcXcpt)
3527 {
3528 AssertLogRelMsgFailedReturn(("hrc=%Rhrc\n", hrcXcpt), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
3529 }
3530
3531#ifdef VBOX_WITH_EXTPACK
3532 /*
3533 * Call the extension pack hooks if everything went well thus far.
3534 */
3535 if (RT_SUCCESS(rc))
3536 {
3537 pAlock->release();
3538 rc = mptrExtPackManager->i_callAllVmConfigureVmmHooks(this, pVM);
3539 pAlock->acquire();
3540 }
3541#endif
3542
3543 /*
3544 * Apply the CFGM overlay.
3545 */
3546 if (RT_SUCCESS(rc))
3547 rc = i_configCfgmOverlay(pRoot, virtualBox, pMachine);
3548
3549 /*
3550 * Dump all extradata API settings tweaks, both global and per VM.
3551 */
3552 if (RT_SUCCESS(rc))
3553 rc = i_configDumpAPISettingsTweaks(virtualBox, pMachine);
3554
3555#undef H
3556
3557 pAlock->release(); /* Avoid triggering the lock order inversion check. */
3558
3559 /*
3560 * Register VM state change handler.
3561 */
3562 int rc2 = VMR3AtStateRegister(pUVM, Console::i_vmstateChangeCallback, this);
3563 AssertRC(rc2);
3564 if (RT_SUCCESS(rc))
3565 rc = rc2;
3566
3567 /*
3568 * Register VM runtime error handler.
3569 */
3570 rc2 = VMR3AtRuntimeErrorRegister(pUVM, Console::i_atVMRuntimeErrorCallback, this);
3571 AssertRC(rc2);
3572 if (RT_SUCCESS(rc))
3573 rc = rc2;
3574
3575 pAlock->acquire();
3576
3577 LogFlowFunc(("vrc = %Rrc\n", rc));
3578 LogFlowFuncLeave();
3579
3580 return rc;
3581}
3582
3583/**
3584 * Retrieves an uint32_t value from the audio driver's extra data branch
3585 * (VBoxInternal2/Audio/DriverName/Value), or, if not found, use global branch
3586 * (VBoxInternal2/Audio/Value).
3587 *
3588 * The driver branch always supersedes the global branch.
3589 * If both branches are not found (empty), return the given default value.
3590 *
3591 * @return VBox status code.
3592 * @param pVirtualBox Pointer to IVirtualBox instance.
3593 * @param pMachine Pointer to IMachine instance.
3594 * @param pszDriverName Audio driver name to retrieve value for.
3595 * @param pszValue Value name to retrieve.
3596 * @param uDefault Default value to return if value not found / invalid.
3597 */
3598uint32_t Console::i_getAudioDriverValU32(IVirtualBox *pVirtualBox, IMachine *pMachine,
3599 const char *pszDriverName, const char *pszValue, uint32_t uDefault)
3600{
3601 Utf8Str strTmp;
3602
3603 Utf8StrFmt strPathDrv("VBoxInternal2/Audio/%s/%s", pszDriverName, pszValue);
3604 GetExtraDataBoth(pVirtualBox, pMachine, strPathDrv.c_str(), &strTmp);
3605 if (strTmp.isEmpty())
3606 {
3607 Utf8StrFmt strPathGlobal("VBoxInternal2/Audio/%s", pszValue);
3608 GetExtraDataBoth(pVirtualBox, pMachine, strPathGlobal.c_str(), &strTmp);
3609 if (strTmp.isNotEmpty())
3610 return strTmp.toUInt32();
3611 }
3612 else /* Return driver-specific value. */
3613 return strTmp.toUInt32();
3614
3615 return uDefault;
3616}
3617
3618/**
3619 * Configures an audio driver via CFGM by getting (optional) values from extra data.
3620 *
3621 * @return VBox status code.
3622 * @param pAudioAdapter Pointer to audio adapter instance. Needed for the driver's input / output configuration.
3623 * @param pVirtualBox Pointer to IVirtualBox instance.
3624 * @param pMachine Pointer to IMachine instance.
3625 * @param pLUN Pointer to CFGM node of LUN (the driver) to configure.
3626 * @param pszDrvName Name of the driver to configure.
3627 */
3628int Console::i_configAudioDriver(IAudioAdapter *pAudioAdapter, IVirtualBox *pVirtualBox, IMachine *pMachine,
3629 PCFGMNODE pLUN, const char *pszDrvName)
3630{
3631#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
3632
3633 HRESULT hrc;
3634
3635 Utf8Str strTmp;
3636 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/Audio/Debug/Enabled", &strTmp);
3637 const uint64_t fDebugEnabled = (strTmp.equalsIgnoreCase("true") || strTmp.equalsIgnoreCase("1")) ? 1 : 0;
3638
3639 BOOL fAudioEnabledIn = FALSE;
3640 hrc = pAudioAdapter->COMGETTER(EnabledIn)(&fAudioEnabledIn); H();
3641 BOOL fAudioEnabledOut = FALSE;
3642 hrc = pAudioAdapter->COMGETTER(EnabledOut)(&fAudioEnabledOut);
3643
3644 InsertConfigString(pLUN, "Driver", "AUDIO");
3645
3646 PCFGMNODE pCfg;
3647 InsertConfigNode(pLUN, "Config", &pCfg);
3648 InsertConfigString (pCfg, "DriverName", pszDrvName);
3649 InsertConfigInteger(pCfg, "InputEnabled", fAudioEnabledIn);
3650 InsertConfigInteger(pCfg, "OutputEnabled", fAudioEnabledOut);
3651
3652 if (fDebugEnabled)
3653 {
3654 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
3655
3656 Utf8Str strDebugPathOut;
3657 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/Audio/Debug/PathOut", &strDebugPathOut);
3658 InsertConfigString(pCfg, "DebugPathOut", strDebugPathOut.c_str());
3659 }
3660
3661
3662 /*
3663 * PCM input parameters (playback + recording).
3664 */
3665
3666 /* Inserts an audio input / output stream's configuration into the CFGM tree. */
3667#define AUDIO_INSERT_DRV_STREAM_CONFIG(a_InOut) \
3668 /* \
3669 * PCM output parameters (playback). \
3670 */ \
3671 InsertConfigInteger(pCfg, "PCMSampleBit" #a_InOut, \
3672 i_getAudioDriverValU32(pVirtualBox, pMachine, pszDrvName, "PCMSampleBit" #a_InOut, 0 /* Default */)); \
3673 InsertConfigInteger(pCfg, "PCMSampleHz" #a_InOut, \
3674 i_getAudioDriverValU32(pVirtualBox, pMachine, pszDrvName, "PCMSampleHz" #a_InOut, 0 /* Default */)); \
3675 InsertConfigInteger(pCfg, "PCMSampleSigned" #a_InOut, \
3676 i_getAudioDriverValU32(pVirtualBox, pMachine, pszDrvName, "PCMSampleSigned" #a_InOut, UINT8_MAX /* Default */)); \
3677 InsertConfigInteger(pCfg, "PCMSampleSwapEndian" #a_InOut, \
3678 i_getAudioDriverValU32(pVirtualBox, pMachine, pszDrvName, "PCMSampleSwapEndian" #a_InOut, UINT8_MAX /* Default */)); \
3679 InsertConfigInteger(pCfg, "PCMSampleChannels" #a_InOut, \
3680 i_getAudioDriverValU32(pVirtualBox, pMachine, pszDrvName, "PCMSampleChannels" #a_InOut, 0 /* Default */)); \
3681 \
3682 /* \
3683 * Buffering stuff. \
3684 */ \
3685 \
3686 InsertConfigInteger(pCfg, "PeriodSizeMs" #a_InOut, \
3687 i_getAudioDriverValU32(pVirtualBox, pMachine, pszDrvName, "PeriodSizeMs" #a_InOut, 0 /* Default */)); \
3688 InsertConfigInteger(pCfg, "BufferSizeMs" #a_InOut, \
3689 i_getAudioDriverValU32(pVirtualBox, pMachine, pszDrvName, "BufferSizeMs" #a_InOut, 0 /* Default */)); \
3690 InsertConfigInteger(pCfg, "PreBufferSizeMs" #a_InOut, \
3691 i_getAudioDriverValU32(pVirtualBox, pMachine, pszDrvName, "PreBufferSizeMs" #a_InOut, UINT32_MAX /* Default */));
3692
3693 AUDIO_INSERT_DRV_STREAM_CONFIG(In);
3694 AUDIO_INSERT_DRV_STREAM_CONFIG(Out);
3695
3696#undef AUDIO_INSERT_DRV_STREAM_CONFIG
3697
3698 PCFGMNODE pLunL1;
3699 InsertConfigNode(pLUN, "AttachedDriver", &pLunL1);
3700
3701 InsertConfigNode(pLunL1, "Config", &pCfg);
3702
3703 Bstr bstrTmp;
3704 hrc = pMachine->COMGETTER(Name)(bstrTmp.asOutParam()); H();
3705 InsertConfigString(pCfg, "StreamName", bstrTmp);
3706
3707 InsertConfigString(pLunL1, "Driver", pszDrvName);
3708
3709 LogFlowFunc(("szDrivName=%s, hrc=%Rhrc\n", pszDrvName, hrc));
3710 return hrc;
3711
3712#undef H
3713}
3714
3715/**
3716 * Applies the CFGM overlay as specified by VBoxInternal/XXX extra data
3717 * values.
3718 *
3719 * @returns VBox status code.
3720 * @param pRoot The root of the configuration tree.
3721 * @param pVirtualBox Pointer to the IVirtualBox interface.
3722 * @param pMachine Pointer to the IMachine interface.
3723 */
3724/* static */
3725int Console::i_configCfgmOverlay(PCFGMNODE pRoot, IVirtualBox *pVirtualBox, IMachine *pMachine)
3726{
3727 /*
3728 * CFGM overlay handling.
3729 *
3730 * Here we check the extra data entries for CFGM values
3731 * and create the nodes and insert the values on the fly. Existing
3732 * values will be removed and reinserted. CFGM is typed, so by default
3733 * we will guess whether it's a string or an integer (byte arrays are
3734 * not currently supported). It's possible to override this autodetection
3735 * by adding "string:", "integer:" or "bytes:" (future).
3736 *
3737 * We first perform a run on global extra data, then on the machine
3738 * extra data to support global settings with local overrides.
3739 */
3740 int rc = VINF_SUCCESS;
3741 try
3742 {
3743 /** @todo add support for removing nodes and byte blobs. */
3744 /*
3745 * Get the next key
3746 */
3747 SafeArray<BSTR> aGlobalExtraDataKeys;
3748 SafeArray<BSTR> aMachineExtraDataKeys;
3749 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
3750 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
3751
3752 // remember the no. of global values so we can call the correct method below
3753 size_t cGlobalValues = aGlobalExtraDataKeys.size();
3754
3755 hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
3756 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
3757
3758 // build a combined list from global keys...
3759 std::list<Utf8Str> llExtraDataKeys;
3760
3761 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); ++i)
3762 llExtraDataKeys.push_back(Utf8Str(aGlobalExtraDataKeys[i]));
3763 // ... and machine keys
3764 for (size_t i = 0; i < aMachineExtraDataKeys.size(); ++i)
3765 llExtraDataKeys.push_back(Utf8Str(aMachineExtraDataKeys[i]));
3766
3767 size_t i2 = 0;
3768 for (std::list<Utf8Str>::const_iterator it = llExtraDataKeys.begin();
3769 it != llExtraDataKeys.end();
3770 ++it, ++i2)
3771 {
3772 const Utf8Str &strKey = *it;
3773
3774 /*
3775 * We only care about keys starting with "VBoxInternal/" (skip "G:" or "M:")
3776 */
3777 if (!strKey.startsWith("VBoxInternal/"))
3778 continue;
3779
3780 const char *pszExtraDataKey = strKey.c_str() + sizeof("VBoxInternal/") - 1;
3781
3782 // get the value
3783 Bstr bstrExtraDataValue;
3784 if (i2 < cGlobalValues)
3785 // this is still one of the global values:
3786 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
3787 bstrExtraDataValue.asOutParam());
3788 else
3789 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
3790 bstrExtraDataValue.asOutParam());
3791 if (FAILED(hrc))
3792 LogRel(("Warning: Cannot get extra data key %s, rc = %Rhrc\n", strKey.c_str(), hrc));
3793
3794 /*
3795 * The key will be in the format "Node1/Node2/Value" or simply "Value".
3796 * Split the two and get the node, delete the value and create the node
3797 * if necessary.
3798 */
3799 PCFGMNODE pNode;
3800 const char *pszCFGMValueName = strrchr(pszExtraDataKey, '/');
3801 if (pszCFGMValueName)
3802 {
3803 /* terminate the node and advance to the value (Utf8Str might not
3804 offically like this but wtf) */
3805 *(char*)pszCFGMValueName = '\0';
3806 ++pszCFGMValueName;
3807
3808 /* does the node already exist? */
3809 pNode = CFGMR3GetChild(pRoot, pszExtraDataKey);
3810 if (pNode)
3811 CFGMR3RemoveValue(pNode, pszCFGMValueName);
3812 else
3813 {
3814 /* create the node */
3815 rc = CFGMR3InsertNode(pRoot, pszExtraDataKey, &pNode);
3816 if (RT_FAILURE(rc))
3817 {
3818 AssertLogRelMsgRC(rc, ("failed to insert node '%s'\n", pszExtraDataKey));
3819 continue;
3820 }
3821 Assert(pNode);
3822 }
3823 }
3824 else
3825 {
3826 /* root value (no node path). */
3827 pNode = pRoot;
3828 pszCFGMValueName = pszExtraDataKey;
3829 pszExtraDataKey--;
3830 CFGMR3RemoveValue(pNode, pszCFGMValueName);
3831 }
3832
3833 /*
3834 * Now let's have a look at the value.
3835 * Empty strings means that we should remove the value, which we've
3836 * already done above.
3837 */
3838 Utf8Str strCFGMValueUtf8(bstrExtraDataValue);
3839 if (!strCFGMValueUtf8.isEmpty())
3840 {
3841 uint64_t u64Value;
3842
3843 /* check for type prefix first. */
3844 if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("string:")))
3845 InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8.c_str() + sizeof("string:") - 1);
3846 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("integer:")))
3847 {
3848 rc = RTStrToUInt64Full(strCFGMValueUtf8.c_str() + sizeof("integer:") - 1, 0, &u64Value);
3849 if (RT_SUCCESS(rc))
3850 rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
3851 }
3852 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("bytes:")))
3853 {
3854 char const *pszBase64 = strCFGMValueUtf8.c_str() + sizeof("bytes:") - 1;
3855 ssize_t cbValue = RTBase64DecodedSize(pszBase64, NULL);
3856 if (cbValue > 0)
3857 {
3858 void *pvBytes = RTMemTmpAlloc(cbValue);
3859 if (pvBytes)
3860 {
3861 rc = RTBase64Decode(pszBase64, pvBytes, cbValue, NULL, NULL);
3862 if (RT_SUCCESS(rc))
3863 rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, pvBytes, cbValue);
3864 RTMemTmpFree(pvBytes);
3865 }
3866 else
3867 rc = VERR_NO_TMP_MEMORY;
3868 }
3869 else if (cbValue == 0)
3870 rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, NULL, 0);
3871 else
3872 rc = VERR_INVALID_BASE64_ENCODING;
3873 }
3874 /* auto detect type. */
3875 else if (RT_SUCCESS(RTStrToUInt64Full(strCFGMValueUtf8.c_str(), 0, &u64Value)))
3876 rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
3877 else
3878 InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8);
3879 AssertLogRelMsgRCBreak(rc, ("failed to insert CFGM value '%s' to key '%s'\n",
3880 strCFGMValueUtf8.c_str(), pszExtraDataKey));
3881 }
3882 }
3883 }
3884 catch (ConfigError &x)
3885 {
3886 // InsertConfig threw something:
3887 return x.m_vrc;
3888 }
3889 return rc;
3890}
3891
3892/**
3893 * Dumps the API settings tweaks as specified by VBoxInternal2/XXX extra data
3894 * values.
3895 *
3896 * @returns VBox status code.
3897 * @param pVirtualBox Pointer to the IVirtualBox interface.
3898 * @param pMachine Pointer to the IMachine interface.
3899 */
3900/* static */
3901int Console::i_configDumpAPISettingsTweaks(IVirtualBox *pVirtualBox, IMachine *pMachine)
3902{
3903 {
3904 SafeArray<BSTR> aGlobalExtraDataKeys;
3905 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
3906 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
3907 bool hasKey = false;
3908 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); i++)
3909 {
3910 Utf8Str strKey(aGlobalExtraDataKeys[i]);
3911 if (!strKey.startsWith("VBoxInternal2/"))
3912 continue;
3913
3914 Bstr bstrValue;
3915 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
3916 bstrValue.asOutParam());
3917 if (FAILED(hrc))
3918 continue;
3919 if (!hasKey)
3920 LogRel(("Global extradata API settings:\n"));
3921 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
3922 hasKey = true;
3923 }
3924 }
3925
3926 {
3927 SafeArray<BSTR> aMachineExtraDataKeys;
3928 HRESULT hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
3929 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
3930 bool hasKey = false;
3931 for (size_t i = 0; i < aMachineExtraDataKeys.size(); i++)
3932 {
3933 Utf8Str strKey(aMachineExtraDataKeys[i]);
3934 if (!strKey.startsWith("VBoxInternal2/"))
3935 continue;
3936
3937 Bstr bstrValue;
3938 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
3939 bstrValue.asOutParam());
3940 if (FAILED(hrc))
3941 continue;
3942 if (!hasKey)
3943 LogRel(("Per-VM extradata API settings:\n"));
3944 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
3945 hasKey = true;
3946 }
3947 }
3948
3949 return VINF_SUCCESS;
3950}
3951
3952int Console::i_configGraphicsController(PCFGMNODE pDevices,
3953 const GraphicsControllerType_T enmGraphicsController,
3954 BusAssignmentManager *pBusMgr,
3955 const ComPtr<IMachine> &ptrMachine,
3956 const ComPtr<IGraphicsAdapter> &ptrGraphicsAdapter,
3957 const ComPtr<IBIOSSettings> &ptrBiosSettings,
3958 bool fHMEnabled)
3959{
3960 // InsertConfig* throws
3961 try
3962 {
3963 PCFGMNODE pDev, pInst, pCfg, pLunL0;
3964 HRESULT hrc;
3965 Bstr bstr;
3966 const char *pcszDevice = "vga";
3967
3968#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
3969 InsertConfigNode(pDevices, pcszDevice, &pDev);
3970 InsertConfigNode(pDev, "0", &pInst);
3971 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3972
3973 hrc = pBusMgr->assignPCIDevice(pcszDevice, pInst); H();
3974 InsertConfigNode(pInst, "Config", &pCfg);
3975 ULONG cVRamMBs;
3976 hrc = ptrGraphicsAdapter->COMGETTER(VRAMSize)(&cVRamMBs); H();
3977 InsertConfigInteger(pCfg, "VRamSize", cVRamMBs * _1M);
3978 ULONG cMonitorCount;
3979 hrc = ptrGraphicsAdapter->COMGETTER(MonitorCount)(&cMonitorCount); H();
3980 InsertConfigInteger(pCfg, "MonitorCount", cMonitorCount);
3981#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
3982 InsertConfigInteger(pCfg, "R0Enabled", fHMEnabled);
3983#else
3984 NOREF(fHMEnabled);
3985#endif
3986 BOOL f3DEnabled;
3987 hrc = ptrGraphicsAdapter->COMGETTER(Accelerate3DEnabled)(&f3DEnabled); H();
3988 InsertConfigInteger(pCfg, "3DEnabled", f3DEnabled);
3989
3990 i_attachStatusDriver(pInst, DeviceType_Graphics3D, 0, 0, NULL, NULL, NULL, 0);
3991
3992#ifdef VBOX_WITH_VMSVGA
3993 if ( enmGraphicsController == GraphicsControllerType_VMSVGA
3994 || enmGraphicsController == GraphicsControllerType_VBoxSVGA)
3995 {
3996 InsertConfigInteger(pCfg, "VMSVGAEnabled", true);
3997 if (enmGraphicsController == GraphicsControllerType_VMSVGA)
3998 {
3999 InsertConfigInteger(pCfg, "VMSVGAPciBarLayout", true);
4000 InsertConfigInteger(pCfg, "VMSVGAPciId", true);
4001 }
4002# ifdef VBOX_WITH_VMSVGA3D
4003 InsertConfigInteger(pCfg, "VMSVGA3dEnabled", f3DEnabled);
4004# else
4005 LogRel(("VMSVGA3d not available in this build!\n"));
4006# endif /* VBOX_WITH_VMSVGA3D */
4007 }
4008#else
4009 RT_NOREF(enmGraphicsController);
4010#endif /* VBOX_WITH_VMSVGA */
4011
4012 /* Custom VESA mode list */
4013 unsigned cModes = 0;
4014 for (unsigned iMode = 1; iMode <= 16; ++iMode)
4015 {
4016 char szExtraDataKey[sizeof("CustomVideoModeXX")];
4017 RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%u", iMode);
4018 hrc = ptrMachine->GetExtraData(Bstr(szExtraDataKey).raw(), bstr.asOutParam()); H();
4019 if (bstr.isEmpty())
4020 break;
4021 InsertConfigString(pCfg, szExtraDataKey, bstr);
4022 ++cModes;
4023 }
4024 InsertConfigInteger(pCfg, "CustomVideoModes", cModes);
4025
4026 /* VESA height reduction */
4027 ULONG ulHeightReduction;
4028 IFramebuffer *pFramebuffer = NULL;
4029 hrc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
4030 if (SUCCEEDED(hrc) && pFramebuffer)
4031 {
4032 hrc = pFramebuffer->COMGETTER(HeightReduction)(&ulHeightReduction); H();
4033 pFramebuffer->Release();
4034 pFramebuffer = NULL;
4035 }
4036 else
4037 {
4038 /* If framebuffer is not available, there is no height reduction. */
4039 ulHeightReduction = 0;
4040 }
4041 InsertConfigInteger(pCfg, "HeightReduction", ulHeightReduction);
4042
4043 /*
4044 * BIOS logo
4045 */
4046 BOOL fFadeIn;
4047 hrc = ptrBiosSettings->COMGETTER(LogoFadeIn)(&fFadeIn); H();
4048 InsertConfigInteger(pCfg, "FadeIn", fFadeIn ? 1 : 0);
4049 BOOL fFadeOut;
4050 hrc = ptrBiosSettings->COMGETTER(LogoFadeOut)(&fFadeOut); H();
4051 InsertConfigInteger(pCfg, "FadeOut", fFadeOut ? 1: 0);
4052 ULONG logoDisplayTime;
4053 hrc = ptrBiosSettings->COMGETTER(LogoDisplayTime)(&logoDisplayTime); H();
4054 InsertConfigInteger(pCfg, "LogoTime", logoDisplayTime);
4055 Bstr logoImagePath;
4056 hrc = ptrBiosSettings->COMGETTER(LogoImagePath)(logoImagePath.asOutParam()); H();
4057 InsertConfigString(pCfg, "LogoFile", Utf8Str(!logoImagePath.isEmpty() ? logoImagePath : "") );
4058
4059 /*
4060 * Boot menu
4061 */
4062 BIOSBootMenuMode_T eBootMenuMode;
4063 int iShowBootMenu;
4064 hrc = ptrBiosSettings->COMGETTER(BootMenuMode)(&eBootMenuMode); H();
4065 switch (eBootMenuMode)
4066 {
4067 case BIOSBootMenuMode_Disabled: iShowBootMenu = 0; break;
4068 case BIOSBootMenuMode_MenuOnly: iShowBootMenu = 1; break;
4069 default: iShowBootMenu = 2; break;
4070 }
4071 InsertConfigInteger(pCfg, "ShowBootMenu", iShowBootMenu);
4072
4073 /* Attach the display. */
4074 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4075 InsertConfigString(pLunL0, "Driver", "MainDisplay");
4076 InsertConfigNode(pLunL0, "Config", &pCfg);
4077 Display *pDisplay = mDisplay;
4078 InsertConfigInteger(pCfg, "Object", (uintptr_t)pDisplay);
4079 }
4080 catch (ConfigError &x)
4081 {
4082 // InsertConfig threw something:
4083 return x.m_vrc;
4084 }
4085
4086#undef H
4087
4088 return VINF_SUCCESS;
4089}
4090
4091
4092/**
4093 * Ellipsis to va_list wrapper for calling setVMRuntimeErrorCallback.
4094 */
4095void Console::i_atVMRuntimeErrorCallbackF(uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)
4096{
4097 va_list va;
4098 va_start(va, pszFormat);
4099 i_atVMRuntimeErrorCallback(NULL, this, fFlags, pszErrorId, pszFormat, va);
4100 va_end(va);
4101}
4102
4103/* XXX introduce RT format specifier */
4104static uint64_t formatDiskSize(uint64_t u64Size, const char **pszUnit)
4105{
4106 if (u64Size > INT64_C(5000)*_1G)
4107 {
4108 *pszUnit = "TB";
4109 return u64Size / _1T;
4110 }
4111 else if (u64Size > INT64_C(5000)*_1M)
4112 {
4113 *pszUnit = "GB";
4114 return u64Size / _1G;
4115 }
4116 else
4117 {
4118 *pszUnit = "MB";
4119 return u64Size / _1M;
4120 }
4121}
4122
4123/**
4124 * Checks the location of the given medium for known bugs affecting the usage
4125 * of the host I/O cache setting.
4126 *
4127 * @returns VBox status code.
4128 * @param pMedium The medium to check.
4129 * @param pfUseHostIOCache Where to store the suggested host I/O cache setting.
4130 */
4131int Console::i_checkMediumLocation(IMedium *pMedium, bool *pfUseHostIOCache)
4132{
4133#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4134 /*
4135 * Some sanity checks.
4136 */
4137 RT_NOREF(pfUseHostIOCache);
4138 ComPtr<IMediumFormat> pMediumFormat;
4139 HRESULT hrc = pMedium->COMGETTER(MediumFormat)(pMediumFormat.asOutParam()); H();
4140 ULONG uCaps = 0;
4141 com::SafeArray <MediumFormatCapabilities_T> mediumFormatCap;
4142 hrc = pMediumFormat->COMGETTER(Capabilities)(ComSafeArrayAsOutParam(mediumFormatCap)); H();
4143
4144 for (ULONG j = 0; j < mediumFormatCap.size(); j++)
4145 uCaps |= mediumFormatCap[j];
4146
4147 if (uCaps & MediumFormatCapabilities_File)
4148 {
4149 Bstr strFile;
4150 hrc = pMedium->COMGETTER(Location)(strFile.asOutParam()); H();
4151 Utf8Str utfFile = Utf8Str(strFile);
4152 Bstr strSnap;
4153 ComPtr<IMachine> pMachine = i_machine();
4154 hrc = pMachine->COMGETTER(SnapshotFolder)(strSnap.asOutParam()); H();
4155 Utf8Str utfSnap = Utf8Str(strSnap);
4156 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
4157 RTFSTYPE enmFsTypeSnap = RTFSTYPE_UNKNOWN;
4158 int rc2 = RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
4159 AssertMsgRCReturn(rc2, ("Querying the file type of '%s' failed!\n", utfFile.c_str()), rc2);
4160 /* Ignore the error code. On error, the file system type is still 'unknown' so
4161 * none of the following paths are taken. This can happen for new VMs which
4162 * still don't have a snapshot folder. */
4163 (void)RTFsQueryType(utfSnap.c_str(), &enmFsTypeSnap);
4164 if (!mfSnapshotFolderDiskTypeShown)
4165 {
4166 LogRel(("File system of '%s' (snapshots) is %s\n",
4167 utfSnap.c_str(), RTFsTypeName(enmFsTypeSnap)));
4168 mfSnapshotFolderDiskTypeShown = true;
4169 }
4170 LogRel(("File system of '%s' is %s\n", utfFile.c_str(), RTFsTypeName(enmFsTypeFile)));
4171 LONG64 i64Size;
4172 hrc = pMedium->COMGETTER(LogicalSize)(&i64Size); H();
4173#ifdef RT_OS_WINDOWS
4174 if ( enmFsTypeFile == RTFSTYPE_FAT
4175 && i64Size >= _4G)
4176 {
4177 const char *pszUnit;
4178 uint64_t u64Print = formatDiskSize((uint64_t)i64Size, &pszUnit);
4179 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
4180 N_("The medium '%ls' has a logical size of %RU64%s "
4181 "but the file system the medium is located on seems "
4182 "to be FAT(32) which cannot handle files bigger than 4GB.\n"
4183 "We strongly recommend to put all your virtual disk images and "
4184 "the snapshot folder onto an NTFS partition"),
4185 strFile.raw(), u64Print, pszUnit);
4186 }
4187#else /* !RT_OS_WINDOWS */
4188 if ( enmFsTypeFile == RTFSTYPE_FAT
4189 || enmFsTypeFile == RTFSTYPE_EXT
4190 || enmFsTypeFile == RTFSTYPE_EXT2
4191 || enmFsTypeFile == RTFSTYPE_EXT3
4192 || enmFsTypeFile == RTFSTYPE_EXT4)
4193 {
4194 RTFILE file;
4195 int rc = RTFileOpen(&file, utfFile.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
4196 if (RT_SUCCESS(rc))
4197 {
4198 RTFOFF maxSize;
4199 /* Careful: This function will work only on selected local file systems! */
4200 rc = RTFileQueryMaxSizeEx(file, &maxSize);
4201 RTFileClose(file);
4202 if ( RT_SUCCESS(rc)
4203 && maxSize > 0
4204 && i64Size > (LONG64)maxSize)
4205 {
4206 const char *pszUnitSiz;
4207 const char *pszUnitMax;
4208 uint64_t u64PrintSiz = formatDiskSize((LONG64)i64Size, &pszUnitSiz);
4209 uint64_t u64PrintMax = formatDiskSize(maxSize, &pszUnitMax);
4210 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected", /* <= not exact but ... */
4211 N_("The medium '%ls' has a logical size of %RU64%s "
4212 "but the file system the medium is located on can "
4213 "only handle files up to %RU64%s in theory.\n"
4214 "We strongly recommend to put all your virtual disk "
4215 "images and the snapshot folder onto a proper "
4216 "file system (e.g. ext3) with a sufficient size"),
4217 strFile.raw(), u64PrintSiz, pszUnitSiz, u64PrintMax, pszUnitMax);
4218 }
4219 }
4220 }
4221#endif /* !RT_OS_WINDOWS */
4222
4223 /*
4224 * Snapshot folder:
4225 * Here we test only for a FAT partition as we had to create a dummy file otherwise
4226 */
4227 if ( enmFsTypeSnap == RTFSTYPE_FAT
4228 && i64Size >= _4G
4229 && !mfSnapshotFolderSizeWarningShown)
4230 {
4231 const char *pszUnit;
4232 uint64_t u64Print = formatDiskSize(i64Size, &pszUnit);
4233 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
4234#ifdef RT_OS_WINDOWS
4235 N_("The snapshot folder of this VM '%ls' seems to be located on "
4236 "a FAT(32) file system. The logical size of the medium '%ls' "
4237 "(%RU64%s) is bigger than the maximum file size this file "
4238 "system can handle (4GB).\n"
4239 "We strongly recommend to put all your virtual disk images and "
4240 "the snapshot folder onto an NTFS partition"),
4241#else
4242 N_("The snapshot folder of this VM '%ls' seems to be located on "
4243 "a FAT(32) file system. The logical size of the medium '%ls' "
4244 "(%RU64%s) is bigger than the maximum file size this file "
4245 "system can handle (4GB).\n"
4246 "We strongly recommend to put all your virtual disk images and "
4247 "the snapshot folder onto a proper file system (e.g. ext3)"),
4248#endif
4249 strSnap.raw(), strFile.raw(), u64Print, pszUnit);
4250 /* Show this particular warning only once */
4251 mfSnapshotFolderSizeWarningShown = true;
4252 }
4253
4254#ifdef RT_OS_LINUX
4255 /*
4256 * Ext4 bug: Check if the host I/O cache is disabled and the disk image is located
4257 * on an ext4 partition.
4258 * This bug apparently applies to the XFS file system as well.
4259 * Linux 2.6.36 is known to be fixed (tested with 2.6.36-rc4).
4260 */
4261
4262 char szOsRelease[128];
4263 int rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOsRelease, sizeof(szOsRelease));
4264 bool fKernelHasODirectBug = RT_FAILURE(rc)
4265 || (RTStrVersionCompare(szOsRelease, "2.6.36-rc4") < 0);
4266
4267 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
4268 && !*pfUseHostIOCache
4269 && fKernelHasODirectBug)
4270 {
4271 if ( enmFsTypeFile == RTFSTYPE_EXT4
4272 || enmFsTypeFile == RTFSTYPE_XFS)
4273 {
4274 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
4275 N_("The host I/O cache for at least one controller is disabled "
4276 "and the medium '%ls' for this VM "
4277 "is located on an %s partition. There is a known Linux "
4278 "kernel bug which can lead to the corruption of the virtual "
4279 "disk image under these conditions.\n"
4280 "Either enable the host I/O cache permanently in the VM "
4281 "settings or put the disk image and the snapshot folder "
4282 "onto a different file system.\n"
4283 "The host I/O cache will now be enabled for this medium"),
4284 strFile.raw(), enmFsTypeFile == RTFSTYPE_EXT4 ? "ext4" : "xfs");
4285 *pfUseHostIOCache = true;
4286 }
4287 else if ( ( enmFsTypeSnap == RTFSTYPE_EXT4
4288 || enmFsTypeSnap == RTFSTYPE_XFS)
4289 && !mfSnapshotFolderExt4WarningShown)
4290 {
4291 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
4292 N_("The host I/O cache for at least one controller is disabled "
4293 "and the snapshot folder for this VM "
4294 "is located on an %s partition. There is a known Linux "
4295 "kernel bug which can lead to the corruption of the virtual "
4296 "disk image under these conditions.\n"
4297 "Either enable the host I/O cache permanently in the VM "
4298 "settings or put the disk image and the snapshot folder "
4299 "onto a different file system.\n"
4300 "The host I/O cache will now be enabled for this medium"),
4301 enmFsTypeSnap == RTFSTYPE_EXT4 ? "ext4" : "xfs");
4302 *pfUseHostIOCache = true;
4303 mfSnapshotFolderExt4WarningShown = true;
4304 }
4305 }
4306
4307 /*
4308 * 2.6.18 bug: Check if the host I/O cache is disabled and the host is running
4309 * Linux 2.6.18. See @bugref{8690}. Apparently the same problem as
4310 * documented in https://lkml.org/lkml/2007/2/1/14. We saw such
4311 * kernel oopses on Linux 2.6.18-416.el5. We don't know when this
4312 * was fixed but we _know_ that 2.6.18 EL5 kernels are affected.
4313 */
4314 bool fKernelAsyncUnreliable = RT_FAILURE(rc)
4315 || (RTStrVersionCompare(szOsRelease, "2.6.19") < 0);
4316 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
4317 && !*pfUseHostIOCache
4318 && fKernelAsyncUnreliable)
4319 {
4320 i_atVMRuntimeErrorCallbackF(0, "Linux2618TooOld",
4321 N_("The host I/O cache for at least one controller is disabled. "
4322 "There is a known Linux kernel bug which can lead to kernel "
4323 "oopses under heavy load. To our knowledge this bug affects "
4324 "all 2.6.18 kernels.\n"
4325 "Either enable the host I/O cache permanently in the VM "
4326 "settings or switch to a newer host kernel.\n"
4327 "The host I/O cache will now be enabled for this medium"));
4328 *pfUseHostIOCache = true;
4329 }
4330#endif
4331 }
4332#undef H
4333
4334 return VINF_SUCCESS;
4335}
4336
4337/**
4338 * Unmounts the specified medium from the specified device.
4339 *
4340 * @returns VBox status code.
4341 * @param pUVM The usermode VM handle.
4342 * @param enmBus The storage bus.
4343 * @param enmDevType The device type.
4344 * @param pcszDevice The device emulation.
4345 * @param uInstance Instance of the device.
4346 * @param uLUN The LUN on the device.
4347 * @param fForceUnmount Whether to force unmounting.
4348 */
4349int Console::i_unmountMediumFromGuest(PUVM pUVM, StorageBus_T enmBus, DeviceType_T enmDevType,
4350 const char *pcszDevice, unsigned uInstance, unsigned uLUN,
4351 bool fForceUnmount)
4352{
4353 /* Unmount existing media only for floppy and DVD drives. */
4354 int rc = VINF_SUCCESS;
4355 PPDMIBASE pBase;
4356 if (enmBus == StorageBus_USB)
4357 rc = PDMR3UsbQueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
4358 else if ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI || enmBus == StorageBus_VirtioSCSI)
4359 || (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD))
4360 rc = PDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
4361 else /* IDE or Floppy */
4362 rc = PDMR3QueryLun(pUVM, pcszDevice, uInstance, uLUN, &pBase);
4363
4364 if (RT_FAILURE(rc))
4365 {
4366 if (rc == VERR_PDM_LUN_NOT_FOUND || rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4367 rc = VINF_SUCCESS;
4368 AssertRC(rc);
4369 }
4370 else
4371 {
4372 PPDMIMOUNT pIMount = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMOUNT);
4373 AssertReturn(pIMount, VERR_INVALID_POINTER);
4374
4375 /* Unmount the media (but do not eject the medium!) */
4376 rc = pIMount->pfnUnmount(pIMount, fForceUnmount, false /*=fEject*/);
4377 if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
4378 rc = VINF_SUCCESS;
4379 /* for example if the medium is locked */
4380 else if (RT_FAILURE(rc))
4381 return rc;
4382 }
4383
4384 return rc;
4385}
4386
4387/**
4388 * Removes the currently attached medium driver form the specified device
4389 * taking care of the controlelr specific configs wrt. to the attached driver chain.
4390 *
4391 * @returns VBox status code.
4392 * @param pCtlInst The controler instance node in the CFGM tree.
4393 * @param pcszDevice The device name.
4394 * @param uInstance The device instance.
4395 * @param uLUN The device LUN.
4396 * @param enmBus The storage bus.
4397 * @param fAttachDetach Flag whether this is a change while the VM is running
4398 * @param fHotplug Flag whether the guest should be notified about the device change.
4399 * @param fForceUnmount Flag whether to force unmounting the medium even if it is locked.
4400 * @param pUVM The usermode VM handle.
4401 * @param enmDevType The device type.
4402 * @param ppLunL0 Where to store the node to attach the new config to on success.
4403 */
4404int Console::i_removeMediumDriverFromVm(PCFGMNODE pCtlInst,
4405 const char *pcszDevice,
4406 unsigned uInstance,
4407 unsigned uLUN,
4408 StorageBus_T enmBus,
4409 bool fAttachDetach,
4410 bool fHotplug,
4411 bool fForceUnmount,
4412 PUVM pUVM,
4413 DeviceType_T enmDevType,
4414 PCFGMNODE *ppLunL0)
4415{
4416 int rc = VINF_SUCCESS;
4417 bool fAddLun = false;
4418
4419 /* First check if the LUN already exists. */
4420 PCFGMNODE pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
4421 AssertReturn(!VALID_PTR(pLunL0) || fAttachDetach, VERR_INTERNAL_ERROR);
4422
4423 if (pLunL0)
4424 {
4425 /*
4426 * Unmount the currently mounted medium if we don't just hot remove the
4427 * complete device (SATA) and it supports unmounting (DVD).
4428 */
4429 if ( (enmDevType != DeviceType_HardDisk)
4430 && !fHotplug)
4431 {
4432 rc = i_unmountMediumFromGuest(pUVM, enmBus, enmDevType, pcszDevice,
4433 uInstance, uLUN, fForceUnmount);
4434 if (RT_FAILURE(rc))
4435 return rc;
4436 }
4437
4438 /*
4439 * Don't detach the SCSI driver when unmounting the current medium
4440 * (we are not ripping out the device but only eject the medium).
4441 */
4442 char *pszDriverDetach = NULL;
4443 if ( !fHotplug
4444 && ( (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD)
4445 || enmBus == StorageBus_SAS
4446 || enmBus == StorageBus_SCSI
4447 || enmBus == StorageBus_VirtioSCSI
4448 || enmBus == StorageBus_USB))
4449 {
4450 /* Get the current attached driver we have to detach. */
4451 PCFGMNODE pDrvLun = CFGMR3GetChildF(pCtlInst, "LUN#%u/AttachedDriver/", uLUN);
4452 if (pDrvLun)
4453 {
4454 char szDriver[128];
4455 RT_ZERO(szDriver);
4456 rc = CFGMR3QueryString(pDrvLun, "Driver", &szDriver[0], sizeof(szDriver));
4457 if (RT_SUCCESS(rc))
4458 pszDriverDetach = RTStrDup(&szDriver[0]);
4459
4460 pLunL0 = pDrvLun;
4461 }
4462 }
4463
4464 if (enmBus == StorageBus_USB)
4465 rc = PDMR3UsbDriverDetach(pUVM, pcszDevice, uInstance, uLUN,
4466 pszDriverDetach, 0 /* iOccurence */,
4467 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
4468 else
4469 rc = PDMR3DriverDetach(pUVM, pcszDevice, uInstance, uLUN,
4470 pszDriverDetach, 0 /* iOccurence */,
4471 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
4472
4473 if (pszDriverDetach)
4474 {
4475 RTStrFree(pszDriverDetach);
4476 /* Remove the complete node and create new for the new config. */
4477 CFGMR3RemoveNode(pLunL0);
4478 pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
4479 if (pLunL0)
4480 {
4481 try
4482 {
4483 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4484 }
4485 catch (ConfigError &x)
4486 {
4487 // InsertConfig threw something:
4488 return x.m_vrc;
4489 }
4490 }
4491 }
4492 if (rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4493 rc = VINF_SUCCESS;
4494 AssertRCReturn(rc, rc);
4495
4496 /*
4497 * Don't remove the LUN except for IDE/floppy/NVMe (which connects directly to the medium driver
4498 * even for DVD devices) or if there is a hotplug event which rips out the complete device.
4499 */
4500 if ( fHotplug
4501 || enmBus == StorageBus_IDE
4502 || enmBus == StorageBus_Floppy
4503 || enmBus == StorageBus_PCIe
4504 || (enmBus == StorageBus_SATA && enmDevType != DeviceType_DVD))
4505 {
4506 fAddLun = true;
4507 CFGMR3RemoveNode(pLunL0);
4508 }
4509 }
4510 else
4511 fAddLun = true;
4512
4513 try
4514 {
4515 if (fAddLun)
4516 InsertConfigNode(pCtlInst, Utf8StrFmt("LUN#%u", uLUN).c_str(), &pLunL0);
4517 }
4518 catch (ConfigError &x)
4519 {
4520 // InsertConfig threw something:
4521 return x.m_vrc;
4522 }
4523
4524 if (ppLunL0)
4525 *ppLunL0 = pLunL0;
4526
4527 return rc;
4528}
4529
4530int Console::i_configMediumAttachment(const char *pcszDevice,
4531 unsigned uInstance,
4532 StorageBus_T enmBus,
4533 bool fUseHostIOCache,
4534 bool fBuiltinIOCache,
4535 bool fInsertDiskIntegrityDrv,
4536 bool fSetupMerge,
4537 unsigned uMergeSource,
4538 unsigned uMergeTarget,
4539 IMediumAttachment *pMediumAtt,
4540 MachineState_T aMachineState,
4541 HRESULT *phrc,
4542 bool fAttachDetach,
4543 bool fForceUnmount,
4544 bool fHotplug,
4545 PUVM pUVM,
4546 DeviceType_T *paLedDevType,
4547 PCFGMNODE *ppLunL0)
4548{
4549 // InsertConfig* throws
4550 try
4551 {
4552 int rc = VINF_SUCCESS;
4553 HRESULT hrc;
4554 Bstr bstr;
4555 PCFGMNODE pCtlInst = NULL;
4556
4557// #define RC_CHECK() AssertMsgReturn(RT_SUCCESS(rc), ("rc=%Rrc\n", rc), rc)
4558#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4559
4560 LONG lDev;
4561 hrc = pMediumAtt->COMGETTER(Device)(&lDev); H();
4562 LONG lPort;
4563 hrc = pMediumAtt->COMGETTER(Port)(&lPort); H();
4564 DeviceType_T lType;
4565 hrc = pMediumAtt->COMGETTER(Type)(&lType); H();
4566 BOOL fNonRotational;
4567 hrc = pMediumAtt->COMGETTER(NonRotational)(&fNonRotational); H();
4568 BOOL fDiscard;
4569 hrc = pMediumAtt->COMGETTER(Discard)(&fDiscard); H();
4570
4571 if (lType == DeviceType_DVD)
4572 fInsertDiskIntegrityDrv = false;
4573
4574 unsigned uLUN;
4575 PCFGMNODE pLunL0 = NULL;
4576 hrc = Console::i_storageBusPortDeviceToLun(enmBus, lPort, lDev, uLUN); H();
4577
4578 /* Determine the base path for the device instance. */
4579 if (enmBus != StorageBus_USB)
4580 pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "Devices/%s/%u/", pcszDevice, uInstance);
4581 else
4582 {
4583 /* If we hotplug a USB device create a new CFGM tree. */
4584 if (!fHotplug)
4585 pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "USB/%s/", pcszDevice);
4586 else
4587 pCtlInst = CFGMR3CreateTree(pUVM);
4588 }
4589 AssertReturn(pCtlInst, VERR_INTERNAL_ERROR);
4590
4591 if (enmBus == StorageBus_USB)
4592 {
4593 PCFGMNODE pCfg = NULL;
4594
4595 /* Create correct instance. */
4596 if (!fHotplug)
4597 {
4598 if (!fAttachDetach)
4599 InsertConfigNode(pCtlInst, Utf8StrFmt("%d", lPort).c_str(), &pCtlInst);
4600 else
4601 pCtlInst = CFGMR3GetChildF(pCtlInst, "%d/", lPort);
4602 }
4603
4604 if (!fAttachDetach)
4605 InsertConfigNode(pCtlInst, "Config", &pCfg);
4606
4607 uInstance = lPort; /* Overwrite uInstance with the correct one. */
4608
4609 if (!fHotplug && !fAttachDetach)
4610 {
4611 char aszUuid[RTUUID_STR_LENGTH + 1];
4612 USBStorageDevice UsbMsd = USBStorageDevice();
4613
4614 memset(aszUuid, 0, sizeof(aszUuid));
4615 rc = RTUuidCreate(&UsbMsd.mUuid);
4616 AssertRCReturn(rc, rc);
4617 rc = RTUuidToStr(&UsbMsd.mUuid, aszUuid, sizeof(aszUuid));
4618 AssertRCReturn(rc, rc);
4619
4620 UsbMsd.iPort = uInstance;
4621
4622 InsertConfigString(pCtlInst, "UUID", aszUuid);
4623 mUSBStorageDevices.push_back(UsbMsd);
4624
4625 /** @todo No LED after hotplugging. */
4626 /* Attach the status driver */
4627 i_attachStatusDriver(pCtlInst, DeviceType_HardDisk, 0, 7, &paLedDevType,
4628 &mapMediumAttachments, pcszDevice, 0);
4629 }
4630 }
4631
4632 rc = i_removeMediumDriverFromVm(pCtlInst, pcszDevice, uInstance, uLUN, enmBus, fAttachDetach,
4633 fHotplug, fForceUnmount, pUVM, lType, &pLunL0);
4634 if (RT_FAILURE(rc))
4635 return rc;
4636 if (ppLunL0)
4637 *ppLunL0 = pLunL0;
4638
4639 Utf8Str devicePath = Utf8StrFmt("%s/%u/LUN#%u", pcszDevice, uInstance, uLUN);
4640 mapMediumAttachments[devicePath] = pMediumAtt;
4641
4642 ComPtr<IMedium> ptrMedium;
4643 hrc = pMediumAtt->COMGETTER(Medium)(ptrMedium.asOutParam()); H();
4644
4645 /*
4646 * 1. Only check this for hard disk images.
4647 * 2. Only check during VM creation and not later, especially not during
4648 * taking an online snapshot!
4649 */
4650 if ( lType == DeviceType_HardDisk
4651 && ( aMachineState == MachineState_Starting
4652 || aMachineState == MachineState_Restoring))
4653 {
4654 rc = i_checkMediumLocation(ptrMedium, &fUseHostIOCache);
4655 if (RT_FAILURE(rc))
4656 return rc;
4657 }
4658
4659 BOOL fPassthrough = FALSE;
4660 if (ptrMedium.isNotNull())
4661 {
4662 BOOL fHostDrive;
4663 hrc = ptrMedium->COMGETTER(HostDrive)(&fHostDrive); H();
4664 if ( ( lType == DeviceType_DVD
4665 || lType == DeviceType_Floppy)
4666 && !fHostDrive)
4667 {
4668 /*
4669 * Informative logging.
4670 */
4671 Bstr strFile;
4672 hrc = ptrMedium->COMGETTER(Location)(strFile.asOutParam()); H();
4673 Utf8Str utfFile = Utf8Str(strFile);
4674 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
4675 (void)RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
4676 LogRel(("File system of '%s' (%s) is %s\n",
4677 utfFile.c_str(), lType == DeviceType_DVD ? "DVD" : "Floppy",
4678 RTFsTypeName(enmFsTypeFile)));
4679 }
4680
4681 if (fHostDrive)
4682 {
4683 hrc = pMediumAtt->COMGETTER(Passthrough)(&fPassthrough); H();
4684 }
4685 }
4686
4687 ComObjPtr<IBandwidthGroup> pBwGroup;
4688 Bstr strBwGroup;
4689 hrc = pMediumAtt->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
4690
4691 if (!pBwGroup.isNull())
4692 {
4693 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
4694 }
4695
4696 /*
4697 * Insert the SCSI driver for hotplug events on the SCSI/USB based storage controllers
4698 * or for SATA if the new device is a CD/DVD drive.
4699 */
4700 if ( (fHotplug || !fAttachDetach)
4701 && ( (enmBus == StorageBus_SCSI || enmBus == StorageBus_SAS || enmBus == StorageBus_USB || enmBus == StorageBus_VirtioSCSI)
4702 || (enmBus == StorageBus_SATA && lType == DeviceType_DVD && !fPassthrough)))
4703 {
4704 InsertConfigString(pLunL0, "Driver", "SCSI");
4705 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4706 }
4707
4708 rc = i_configMedium(pLunL0,
4709 !!fPassthrough,
4710 lType,
4711 fUseHostIOCache,
4712 fBuiltinIOCache,
4713 fInsertDiskIntegrityDrv,
4714 fSetupMerge,
4715 uMergeSource,
4716 uMergeTarget,
4717 strBwGroup.isEmpty() ? NULL : Utf8Str(strBwGroup).c_str(),
4718 !!fDiscard,
4719 !!fNonRotational,
4720 ptrMedium,
4721 aMachineState,
4722 phrc);
4723 if (RT_FAILURE(rc))
4724 return rc;
4725
4726 if (fAttachDetach)
4727 {
4728 /* Attach the new driver. */
4729 if (enmBus == StorageBus_USB)
4730 {
4731 if (fHotplug)
4732 {
4733 USBStorageDevice UsbMsd = USBStorageDevice();
4734 RTUuidCreate(&UsbMsd.mUuid);
4735 UsbMsd.iPort = uInstance;
4736 rc = PDMR3UsbCreateEmulatedDevice(pUVM, pcszDevice, pCtlInst, &UsbMsd.mUuid, NULL);
4737 if (RT_SUCCESS(rc))
4738 mUSBStorageDevices.push_back(UsbMsd);
4739 }
4740 else
4741 rc = PDMR3UsbDriverAttach(pUVM, pcszDevice, uInstance, uLUN,
4742 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4743 }
4744 else if ( !fHotplug
4745 && ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI || enmBus == StorageBus_VirtioSCSI)
4746 || (enmBus == StorageBus_SATA && lType == DeviceType_DVD)))
4747 rc = PDMR3DriverAttach(pUVM, pcszDevice, uInstance, uLUN,
4748 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4749 else
4750 rc = PDMR3DeviceAttach(pUVM, pcszDevice, uInstance, uLUN,
4751 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4752 AssertRCReturn(rc, rc);
4753
4754 /*
4755 * Make the secret key helper interface known to the VD driver if it is attached,
4756 * so we can get notified about missing keys.
4757 */
4758 PPDMIBASE pIBase = NULL;
4759 rc = PDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "VD", &pIBase);
4760 if (RT_SUCCESS(rc) && pIBase)
4761 {
4762 PPDMIMEDIA pIMedium = (PPDMIMEDIA)pIBase->pfnQueryInterface(pIBase, PDMIMEDIA_IID);
4763 if (pIMedium)
4764 {
4765 rc = pIMedium->pfnSetSecKeyIf(pIMedium, mpIfSecKey, mpIfSecKeyHlp);
4766 Assert(RT_SUCCESS(rc) || rc == VERR_NOT_SUPPORTED);
4767 }
4768 }
4769
4770 /* There is no need to handle removable medium mounting, as we
4771 * unconditionally replace everthing including the block driver level.
4772 * This means the new medium will be picked up automatically. */
4773 }
4774
4775 if (paLedDevType)
4776 paLedDevType[uLUN] = lType;
4777
4778 /* Dump the changed LUN if possible, dump the complete device otherwise */
4779 if ( aMachineState != MachineState_Starting
4780 && aMachineState != MachineState_Restoring)
4781 CFGMR3Dump(pLunL0 ? pLunL0 : pCtlInst);
4782 }
4783 catch (ConfigError &x)
4784 {
4785 // InsertConfig threw something:
4786 return x.m_vrc;
4787 }
4788
4789#undef H
4790
4791 return VINF_SUCCESS;
4792}
4793
4794int Console::i_configMedium(PCFGMNODE pLunL0,
4795 bool fPassthrough,
4796 DeviceType_T enmType,
4797 bool fUseHostIOCache,
4798 bool fBuiltinIOCache,
4799 bool fInsertDiskIntegrityDrv,
4800 bool fSetupMerge,
4801 unsigned uMergeSource,
4802 unsigned uMergeTarget,
4803 const char *pcszBwGroup,
4804 bool fDiscard,
4805 bool fNonRotational,
4806 ComPtr<IMedium> ptrMedium,
4807 MachineState_T aMachineState,
4808 HRESULT *phrc)
4809{
4810 // InsertConfig* throws
4811 try
4812 {
4813 HRESULT hrc;
4814 Bstr bstr;
4815 PCFGMNODE pCfg = NULL;
4816
4817#define H() \
4818 AssertMsgReturnStmt(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), if (phrc) *phrc = hrc, Global::vboxStatusCodeFromCOM(hrc))
4819
4820
4821 BOOL fHostDrive = FALSE;
4822 MediumType_T mediumType = MediumType_Normal;
4823 if (ptrMedium.isNotNull())
4824 {
4825 hrc = ptrMedium->COMGETTER(HostDrive)(&fHostDrive); H();
4826 hrc = ptrMedium->COMGETTER(Type)(&mediumType); H();
4827 }
4828
4829 if (fHostDrive)
4830 {
4831 Assert(ptrMedium.isNotNull());
4832 if (enmType == DeviceType_DVD)
4833 {
4834 InsertConfigString(pLunL0, "Driver", "HostDVD");
4835 InsertConfigNode(pLunL0, "Config", &pCfg);
4836
4837 hrc = ptrMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4838 InsertConfigString(pCfg, "Path", bstr);
4839
4840 InsertConfigInteger(pCfg, "Passthrough", fPassthrough);
4841 }
4842 else if (enmType == DeviceType_Floppy)
4843 {
4844 InsertConfigString(pLunL0, "Driver", "HostFloppy");
4845 InsertConfigNode(pLunL0, "Config", &pCfg);
4846
4847 hrc = ptrMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4848 InsertConfigString(pCfg, "Path", bstr);
4849 }
4850 }
4851 else
4852 {
4853 if (fInsertDiskIntegrityDrv)
4854 {
4855 /*
4856 * The actual configuration is done through CFGM extra data
4857 * for each inserted driver separately.
4858 */
4859 InsertConfigString(pLunL0, "Driver", "DiskIntegrity");
4860 InsertConfigNode(pLunL0, "Config", &pCfg);
4861 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4862 }
4863
4864 InsertConfigString(pLunL0, "Driver", "VD");
4865 InsertConfigNode(pLunL0, "Config", &pCfg);
4866 switch (enmType)
4867 {
4868 case DeviceType_DVD:
4869 InsertConfigString(pCfg, "Type", "DVD");
4870 InsertConfigInteger(pCfg, "Mountable", 1);
4871 break;
4872 case DeviceType_Floppy:
4873 InsertConfigString(pCfg, "Type", "Floppy 1.44");
4874 InsertConfigInteger(pCfg, "Mountable", 1);
4875 break;
4876 case DeviceType_HardDisk:
4877 default:
4878 InsertConfigString(pCfg, "Type", "HardDisk");
4879 InsertConfigInteger(pCfg, "Mountable", 0);
4880 }
4881
4882 if ( ptrMedium.isNotNull()
4883 && ( enmType == DeviceType_DVD
4884 || enmType == DeviceType_Floppy)
4885 )
4886 {
4887 // if this medium represents an ISO image and this image is inaccessible,
4888 // the ignore it instead of causing a failure; this can happen when we
4889 // restore a VM state and the ISO has disappeared, e.g. because the Guest
4890 // Additions were mounted and the user upgraded VirtualBox. Previously
4891 // we failed on startup, but that's not good because the only way out then
4892 // would be to discard the VM state...
4893 MediumState_T mediumState;
4894 hrc = ptrMedium->RefreshState(&mediumState); H();
4895 if (mediumState == MediumState_Inaccessible)
4896 {
4897 Bstr loc;
4898 hrc = ptrMedium->COMGETTER(Location)(loc.asOutParam()); H();
4899 i_atVMRuntimeErrorCallbackF(0, "DvdOrFloppyImageInaccessible",
4900 "The image file '%ls' is inaccessible and is being ignored. "
4901 "Please select a different image file for the virtual %s drive.",
4902 loc.raw(),
4903 enmType == DeviceType_DVD ? "DVD" : "floppy");
4904 ptrMedium.setNull();
4905 }
4906 }
4907
4908 if (ptrMedium.isNotNull())
4909 {
4910 /* Start with length of parent chain, as the list is reversed */
4911 unsigned uImage = 0;
4912 ComPtr<IMedium> ptrTmp = ptrMedium;
4913 while (ptrTmp.isNotNull())
4914 {
4915 uImage++;
4916 ComPtr<IMedium> ptrParent;
4917 hrc = ptrTmp->COMGETTER(Parent)(ptrParent.asOutParam()); H();
4918 ptrTmp = ptrParent;
4919 }
4920 /* Index of last image */
4921 uImage--;
4922
4923# ifdef VBOX_WITH_EXTPACK
4924 if (mptrExtPackManager->i_isExtPackUsable(ORACLE_PUEL_EXTPACK_NAME))
4925 {
4926 /* Configure loading the VDPlugin. */
4927 static const char s_szVDPlugin[] = "VDPluginCrypt";
4928 PCFGMNODE pCfgPlugins = NULL;
4929 PCFGMNODE pCfgPlugin = NULL;
4930 Utf8Str strPlugin;
4931 hrc = mptrExtPackManager->i_getLibraryPathForExtPack(s_szVDPlugin, ORACLE_PUEL_EXTPACK_NAME, &strPlugin);
4932 // Don't fail, this is optional!
4933 if (SUCCEEDED(hrc))
4934 {
4935 InsertConfigNode(pCfg, "Plugins", &pCfgPlugins);
4936 InsertConfigNode(pCfgPlugins, s_szVDPlugin, &pCfgPlugin);
4937 InsertConfigString(pCfgPlugin, "Path", strPlugin.c_str());
4938 }
4939 }
4940# endif
4941
4942 hrc = ptrMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4943 InsertConfigString(pCfg, "Path", bstr);
4944
4945 hrc = ptrMedium->COMGETTER(Format)(bstr.asOutParam()); H();
4946 InsertConfigString(pCfg, "Format", bstr);
4947
4948 if (mediumType == MediumType_Readonly)
4949 InsertConfigInteger(pCfg, "ReadOnly", 1);
4950 else if (enmType == DeviceType_Floppy)
4951 InsertConfigInteger(pCfg, "MaybeReadOnly", 1);
4952
4953 /* Start without exclusive write access to the images. */
4954 /** @todo Live Migration: I don't quite like this, we risk screwing up when
4955 * we're resuming the VM if some 3rd dude have any of the VDIs open
4956 * with write sharing denied. However, if the two VMs are sharing a
4957 * image it really is necessary....
4958 *
4959 * So, on the "lock-media" command, the target teleporter should also
4960 * make DrvVD undo TempReadOnly. It gets interesting if we fail after
4961 * that. Grumble. */
4962 if ( enmType == DeviceType_HardDisk
4963 && aMachineState == MachineState_TeleportingIn)
4964 InsertConfigInteger(pCfg, "TempReadOnly", 1);
4965
4966 /* Flag for opening the medium for sharing between VMs. This
4967 * is done at the moment only for the first (and only) medium
4968 * in the chain, as shared media can have no diffs. */
4969 if (mediumType == MediumType_Shareable)
4970 InsertConfigInteger(pCfg, "Shareable", 1);
4971
4972 if (!fUseHostIOCache)
4973 {
4974 InsertConfigInteger(pCfg, "UseNewIo", 1);
4975 /*
4976 * Activate the builtin I/O cache for harddisks only.
4977 * It caches writes only which doesn't make sense for DVD drives
4978 * and just increases the overhead.
4979 */
4980 if ( fBuiltinIOCache
4981 && (enmType == DeviceType_HardDisk))
4982 InsertConfigInteger(pCfg, "BlockCache", 1);
4983 }
4984
4985 if (fSetupMerge)
4986 {
4987 InsertConfigInteger(pCfg, "SetupMerge", 1);
4988 if (uImage == uMergeSource)
4989 InsertConfigInteger(pCfg, "MergeSource", 1);
4990 else if (uImage == uMergeTarget)
4991 InsertConfigInteger(pCfg, "MergeTarget", 1);
4992 }
4993
4994 if (pcszBwGroup)
4995 InsertConfigString(pCfg, "BwGroup", pcszBwGroup);
4996
4997 if (fDiscard)
4998 InsertConfigInteger(pCfg, "Discard", 1);
4999
5000 if (fNonRotational)
5001 InsertConfigInteger(pCfg, "NonRotationalMedium", 1);
5002
5003 /* Pass all custom parameters. */
5004 bool fHostIP = true;
5005 bool fEncrypted = false;
5006 hrc = i_configMediumProperties(pCfg, ptrMedium, &fHostIP, &fEncrypted); H();
5007
5008 /* Create an inverted list of parents. */
5009 uImage--;
5010 ComPtr<IMedium> ptrParentMedium = ptrMedium;
5011 for (PCFGMNODE pParent = pCfg;; uImage--)
5012 {
5013 ComPtr<IMedium> ptrCurMedium;
5014 hrc = ptrParentMedium->COMGETTER(Parent)(ptrCurMedium.asOutParam()); H();
5015 if (ptrCurMedium.isNull())
5016 break;
5017
5018 PCFGMNODE pCur;
5019 InsertConfigNode(pParent, "Parent", &pCur);
5020 hrc = ptrCurMedium->COMGETTER(Location)(bstr.asOutParam()); H();
5021 InsertConfigString(pCur, "Path", bstr);
5022
5023 hrc = ptrCurMedium->COMGETTER(Format)(bstr.asOutParam()); H();
5024 InsertConfigString(pCur, "Format", bstr);
5025
5026 if (fSetupMerge)
5027 {
5028 if (uImage == uMergeSource)
5029 InsertConfigInteger(pCur, "MergeSource", 1);
5030 else if (uImage == uMergeTarget)
5031 InsertConfigInteger(pCur, "MergeTarget", 1);
5032 }
5033
5034 /* Configure medium properties. */
5035 hrc = i_configMediumProperties(pCur, ptrCurMedium, &fHostIP, &fEncrypted); H();
5036
5037 /* next */
5038 pParent = pCur;
5039 ptrParentMedium = ptrCurMedium;
5040 }
5041
5042 /* Custom code: put marker to not use host IP stack to driver
5043 * configuration node. Simplifies life of DrvVD a bit. */
5044 if (!fHostIP)
5045 InsertConfigInteger(pCfg, "HostIPStack", 0);
5046
5047 if (fEncrypted)
5048 m_cDisksEncrypted++;
5049 }
5050 else
5051 {
5052 /* Set empty drive flag for DVD or floppy without media. */
5053 if ( enmType == DeviceType_DVD
5054 || enmType == DeviceType_Floppy)
5055 InsertConfigInteger(pCfg, "EmptyDrive", 1);
5056 }
5057 }
5058#undef H
5059 }
5060 catch (ConfigError &x)
5061 {
5062 // InsertConfig threw something:
5063 return x.m_vrc;
5064 }
5065
5066 return VINF_SUCCESS;
5067}
5068
5069/**
5070 * Adds the medium properties to the CFGM tree.
5071 *
5072 * @returns VBox status code.
5073 * @param pCur The current CFGM node.
5074 * @param pMedium The medium object to configure.
5075 * @param pfHostIP Where to return the value of the \"HostIPStack\" property if found.
5076 * @param pfEncrypted Where to return whether the medium is encrypted.
5077 */
5078int Console::i_configMediumProperties(PCFGMNODE pCur, IMedium *pMedium, bool *pfHostIP, bool *pfEncrypted)
5079{
5080 /* Pass all custom parameters. */
5081 SafeArray<BSTR> aNames;
5082 SafeArray<BSTR> aValues;
5083 HRESULT hrc = pMedium->GetProperties(NULL, ComSafeArrayAsOutParam(aNames),
5084 ComSafeArrayAsOutParam(aValues));
5085
5086 if ( SUCCEEDED(hrc)
5087 && aNames.size() != 0)
5088 {
5089 PCFGMNODE pVDC;
5090 InsertConfigNode(pCur, "VDConfig", &pVDC);
5091 for (size_t ii = 0; ii < aNames.size(); ++ii)
5092 {
5093 if (aValues[ii] && *aValues[ii])
5094 {
5095 Utf8Str name = aNames[ii];
5096 Utf8Str value = aValues[ii];
5097 size_t offSlash = name.find("/", 0);
5098 if ( offSlash != name.npos
5099 && !name.startsWith("Special/"))
5100 {
5101 com::Utf8Str strFilter;
5102 com::Utf8Str strKey;
5103
5104 hrc = strFilter.assignEx(name, 0, offSlash);
5105 if (FAILED(hrc))
5106 break;
5107
5108 hrc = strKey.assignEx(name, offSlash + 1, name.length() - offSlash - 1); /* Skip slash */
5109 if (FAILED(hrc))
5110 break;
5111
5112 PCFGMNODE pCfgFilterConfig = CFGMR3GetChild(pVDC, strFilter.c_str());
5113 if (!pCfgFilterConfig)
5114 InsertConfigNode(pVDC, strFilter.c_str(), &pCfgFilterConfig);
5115
5116 InsertConfigString(pCfgFilterConfig, strKey.c_str(), value);
5117 }
5118 else
5119 {
5120 InsertConfigString(pVDC, name.c_str(), value);
5121 if ( name.compare("HostIPStack") == 0
5122 && value.compare("0") == 0)
5123 *pfHostIP = false;
5124 }
5125
5126 if ( name.compare("CRYPT/KeyId") == 0
5127 && pfEncrypted)
5128 *pfEncrypted = true;
5129 }
5130 }
5131 }
5132
5133 return hrc;
5134}
5135
5136
5137/**
5138 * Construct the Network configuration tree
5139 *
5140 * @returns VBox status code.
5141 *
5142 * @param pszDevice The PDM device name.
5143 * @param uInstance The PDM device instance.
5144 * @param uLun The PDM LUN number of the drive.
5145 * @param aNetworkAdapter The network adapter whose attachment needs to be changed
5146 * @param pCfg Configuration node for the device
5147 * @param pLunL0 To store the pointer to the LUN#0.
5148 * @param pInst The instance CFGM node
5149 * @param fAttachDetach To determine if the network attachment should
5150 * be attached/detached after/before
5151 * configuration.
5152 * @param fIgnoreConnectFailure
5153 * True if connection failures should be ignored
5154 * (makes only sense for bridged/host-only networks).
5155 *
5156 * @note Locks this object for writing.
5157 * @thread EMT
5158 */
5159int Console::i_configNetwork(const char *pszDevice,
5160 unsigned uInstance,
5161 unsigned uLun,
5162 INetworkAdapter *aNetworkAdapter,
5163 PCFGMNODE pCfg,
5164 PCFGMNODE pLunL0,
5165 PCFGMNODE pInst,
5166 bool fAttachDetach,
5167 bool fIgnoreConnectFailure)
5168{
5169 RT_NOREF(fIgnoreConnectFailure);
5170 AutoCaller autoCaller(this);
5171 AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED);
5172
5173 // InsertConfig* throws
5174 try
5175 {
5176 int rc = VINF_SUCCESS;
5177 HRESULT hrc;
5178 Bstr bstr;
5179
5180#ifdef VBOX_WITH_CLOUD_NET
5181 /* We'll need device's pCfg for cloud attachments */
5182 PCFGMNODE pDevCfg = pCfg;
5183#endif /* VBOX_WITH_CLOUD_NET */
5184
5185#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
5186
5187 /*
5188 * Locking the object before doing VMR3* calls is quite safe here, since
5189 * we're on EMT. Write lock is necessary because we indirectly modify the
5190 * meAttachmentType member.
5191 */
5192 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
5193
5194 ComPtr<IMachine> pMachine = i_machine();
5195
5196 ComPtr<IVirtualBox> virtualBox;
5197 hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam()); H();
5198
5199 ComPtr<IHost> host;
5200 hrc = virtualBox->COMGETTER(Host)(host.asOutParam()); H();
5201
5202 BOOL fSniffer;
5203 hrc = aNetworkAdapter->COMGETTER(TraceEnabled)(&fSniffer); H();
5204
5205 NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy;
5206 hrc = aNetworkAdapter->COMGETTER(PromiscModePolicy)(&enmPromiscModePolicy); H();
5207 const char *pszPromiscuousGuestPolicy;
5208 switch (enmPromiscModePolicy)
5209 {
5210 case NetworkAdapterPromiscModePolicy_Deny: pszPromiscuousGuestPolicy = "deny"; break;
5211 case NetworkAdapterPromiscModePolicy_AllowNetwork: pszPromiscuousGuestPolicy = "allow-network"; break;
5212 case NetworkAdapterPromiscModePolicy_AllowAll: pszPromiscuousGuestPolicy = "allow-all"; break;
5213 default: AssertFailedReturn(VERR_INTERNAL_ERROR_4);
5214 }
5215
5216 if (fAttachDetach)
5217 {
5218 rc = PDMR3DeviceDetach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/);
5219 if (rc == VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN)
5220 rc = VINF_SUCCESS;
5221 AssertLogRelRCReturn(rc, rc);
5222
5223 /* Nuke anything which might have been left behind. */
5224 CFGMR3RemoveNode(CFGMR3GetChildF(pInst, "LUN#%u", uLun));
5225 }
5226
5227#ifdef VBOX_WITH_NETSHAPER
5228 ComObjPtr<IBandwidthGroup> pBwGroup;
5229 Bstr strBwGroup;
5230 hrc = aNetworkAdapter->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
5231
5232 if (!pBwGroup.isNull())
5233 {
5234 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
5235 }
5236#endif /* VBOX_WITH_NETSHAPER */
5237
5238 AssertMsg(uLun == 0, ("Network attachments with LUN > 0 are not supported yet\n"));
5239 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", uLun);
5240
5241#ifdef VBOX_WITH_NETSHAPER
5242 if (!strBwGroup.isEmpty())
5243 {
5244 InsertConfigString(pLunL0, "Driver", "NetShaper");
5245 InsertConfigNode(pLunL0, "Config", &pCfg);
5246 InsertConfigString(pCfg, "BwGroup", strBwGroup);
5247 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
5248 }
5249#endif /* VBOX_WITH_NETSHAPER */
5250
5251 if (fSniffer)
5252 {
5253 InsertConfigString(pLunL0, "Driver", "NetSniffer");
5254 InsertConfigNode(pLunL0, "Config", &pCfg);
5255 hrc = aNetworkAdapter->COMGETTER(TraceFile)(bstr.asOutParam()); H();
5256 if (!bstr.isEmpty()) /* check convention for indicating default file. */
5257 InsertConfigString(pCfg, "File", bstr);
5258 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
5259 }
5260
5261
5262 Bstr networkName, trunkName, trunkType;
5263 NetworkAttachmentType_T eAttachmentType;
5264 hrc = aNetworkAdapter->COMGETTER(AttachmentType)(&eAttachmentType); H();
5265 switch (eAttachmentType)
5266 {
5267 case NetworkAttachmentType_Null:
5268 break;
5269
5270 case NetworkAttachmentType_NAT:
5271 {
5272 ComPtr<INATEngine> natEngine;
5273 hrc = aNetworkAdapter->COMGETTER(NATEngine)(natEngine.asOutParam()); H();
5274 InsertConfigString(pLunL0, "Driver", "NAT");
5275 InsertConfigNode(pLunL0, "Config", &pCfg);
5276
5277 /* Configure TFTP prefix and boot filename. */
5278 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
5279 if (!bstr.isEmpty())
5280 InsertConfigString(pCfg, "TFTPPrefix", Utf8StrFmt("%ls%c%s", bstr.raw(), RTPATH_DELIMITER, "TFTP"));
5281 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
5282 InsertConfigString(pCfg, "BootFile", Utf8StrFmt("%ls.pxe", bstr.raw()));
5283
5284 hrc = natEngine->COMGETTER(Network)(bstr.asOutParam()); H();
5285 if (!bstr.isEmpty())
5286 InsertConfigString(pCfg, "Network", bstr);
5287 else
5288 {
5289 ULONG uSlot;
5290 hrc = aNetworkAdapter->COMGETTER(Slot)(&uSlot); H();
5291 InsertConfigString(pCfg, "Network", Utf8StrFmt("10.0.%d.0/24", uSlot+2));
5292 }
5293 hrc = natEngine->COMGETTER(HostIP)(bstr.asOutParam()); H();
5294 if (!bstr.isEmpty())
5295 InsertConfigString(pCfg, "BindIP", bstr);
5296 ULONG mtu = 0;
5297 ULONG sockSnd = 0;
5298 ULONG sockRcv = 0;
5299 ULONG tcpSnd = 0;
5300 ULONG tcpRcv = 0;
5301 hrc = natEngine->GetNetworkSettings(&mtu, &sockSnd, &sockRcv, &tcpSnd, &tcpRcv); H();
5302 if (mtu)
5303 InsertConfigInteger(pCfg, "SlirpMTU", mtu);
5304 if (sockRcv)
5305 InsertConfigInteger(pCfg, "SockRcv", sockRcv);
5306 if (sockSnd)
5307 InsertConfigInteger(pCfg, "SockSnd", sockSnd);
5308 if (tcpRcv)
5309 InsertConfigInteger(pCfg, "TcpRcv", tcpRcv);
5310 if (tcpSnd)
5311 InsertConfigInteger(pCfg, "TcpSnd", tcpSnd);
5312 hrc = natEngine->COMGETTER(TFTPPrefix)(bstr.asOutParam()); H();
5313 if (!bstr.isEmpty())
5314 {
5315 RemoveConfigValue(pCfg, "TFTPPrefix");
5316 InsertConfigString(pCfg, "TFTPPrefix", bstr);
5317 }
5318 hrc = natEngine->COMGETTER(TFTPBootFile)(bstr.asOutParam()); H();
5319 if (!bstr.isEmpty())
5320 {
5321 RemoveConfigValue(pCfg, "BootFile");
5322 InsertConfigString(pCfg, "BootFile", bstr);
5323 }
5324 hrc = natEngine->COMGETTER(TFTPNextServer)(bstr.asOutParam()); H();
5325 if (!bstr.isEmpty())
5326 InsertConfigString(pCfg, "NextServer", bstr);
5327 BOOL fDNSFlag;
5328 hrc = natEngine->COMGETTER(DNSPassDomain)(&fDNSFlag); H();
5329 InsertConfigInteger(pCfg, "PassDomain", fDNSFlag);
5330 hrc = natEngine->COMGETTER(DNSProxy)(&fDNSFlag); H();
5331 InsertConfigInteger(pCfg, "DNSProxy", fDNSFlag);
5332 hrc = natEngine->COMGETTER(DNSUseHostResolver)(&fDNSFlag); H();
5333 InsertConfigInteger(pCfg, "UseHostResolver", fDNSFlag);
5334
5335 ULONG aliasMode;
5336 hrc = natEngine->COMGETTER(AliasMode)(&aliasMode); H();
5337 InsertConfigInteger(pCfg, "AliasMode", aliasMode);
5338
5339 /* port-forwarding */
5340 SafeArray<BSTR> pfs;
5341 hrc = natEngine->COMGETTER(Redirects)(ComSafeArrayAsOutParam(pfs)); H();
5342
5343 PCFGMNODE pPFTree = NULL;
5344 if (pfs.size() > 0)
5345 InsertConfigNode(pCfg, "PortForwarding", &pPFTree);
5346
5347 for (unsigned int i = 0; i < pfs.size(); ++i)
5348 {
5349 PCFGMNODE pPF = NULL; /* /Devices/Dev/.../Config/PortForwarding/$n/ */
5350
5351 uint16_t port = 0;
5352 Utf8Str utf = pfs[i];
5353 Utf8Str strName;
5354 Utf8Str strProto;
5355 Utf8Str strHostPort;
5356 Utf8Str strHostIP;
5357 Utf8Str strGuestPort;
5358 Utf8Str strGuestIP;
5359 size_t pos, ppos;
5360 pos = ppos = 0;
5361#define ITERATE_TO_NEXT_TERM(res, str, pos, ppos) \
5362 { \
5363 pos = str.find(",", ppos); \
5364 if (pos == Utf8Str::npos) \
5365 { \
5366 Log(( #res " extracting from %s is failed\n", str.c_str())); \
5367 continue; \
5368 } \
5369 res = str.substr(ppos, pos - ppos); \
5370 Log2((#res " %s pos:%d, ppos:%d\n", res.c_str(), pos, ppos)); \
5371 ppos = pos + 1; \
5372 } /* no do { ... } while because of 'continue' */
5373 ITERATE_TO_NEXT_TERM(strName, utf, pos, ppos);
5374 ITERATE_TO_NEXT_TERM(strProto, utf, pos, ppos);
5375 ITERATE_TO_NEXT_TERM(strHostIP, utf, pos, ppos);
5376 ITERATE_TO_NEXT_TERM(strHostPort, utf, pos, ppos);
5377 ITERATE_TO_NEXT_TERM(strGuestIP, utf, pos, ppos);
5378 strGuestPort = utf.substr(ppos, utf.length() - ppos);
5379#undef ITERATE_TO_NEXT_TERM
5380
5381 uint32_t proto = strProto.toUInt32();
5382 bool fValid = true;
5383 switch (proto)
5384 {
5385 case NATProtocol_UDP:
5386 strProto = "UDP";
5387 break;
5388 case NATProtocol_TCP:
5389 strProto = "TCP";
5390 break;
5391 default:
5392 fValid = false;
5393 }
5394 /* continue with next rule if no valid proto was passed */
5395 if (!fValid)
5396 continue;
5397
5398 InsertConfigNode(pPFTree, Utf8StrFmt("%u", i).c_str(), &pPF);
5399
5400 if (!strName.isEmpty())
5401 InsertConfigString(pPF, "Name", strName);
5402
5403 InsertConfigString(pPF, "Protocol", strProto);
5404
5405 if (!strHostIP.isEmpty())
5406 InsertConfigString(pPF, "BindIP", strHostIP);
5407
5408 if (!strGuestIP.isEmpty())
5409 InsertConfigString(pPF, "GuestIP", strGuestIP);
5410
5411 port = RTStrToUInt16(strHostPort.c_str());
5412 if (port)
5413 InsertConfigInteger(pPF, "HostPort", port);
5414
5415 port = RTStrToUInt16(strGuestPort.c_str());
5416 if (port)
5417 InsertConfigInteger(pPF, "GuestPort", port);
5418 }
5419 break;
5420 }
5421
5422 case NetworkAttachmentType_Bridged:
5423 {
5424#if (defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)) && !defined(VBOX_WITH_NETFLT)
5425 hrc = i_attachToTapInterface(aNetworkAdapter);
5426 if (FAILED(hrc))
5427 {
5428 switch (hrc)
5429 {
5430 case VERR_ACCESS_DENIED:
5431 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5432 "Failed to open '/dev/net/tun' for read/write access. Please check the "
5433 "permissions of that node. Either run 'chmod 0666 /dev/net/tun' or "
5434 "change the group of that node and make yourself a member of that group. Make "
5435 "sure that these changes are permanent, especially if you are "
5436 "using udev"));
5437 default:
5438 AssertMsgFailed(("Could not attach to host interface! Bad!\n"));
5439 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5440 "Failed to initialize Host Interface Networking"));
5441 }
5442 }
5443
5444 Assert((intptr_t)maTapFD[uInstance] >= 0);
5445 if ((intptr_t)maTapFD[uInstance] >= 0)
5446 {
5447 InsertConfigString(pLunL0, "Driver", "HostInterface");
5448 InsertConfigNode(pLunL0, "Config", &pCfg);
5449 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
5450 }
5451
5452#elif defined(VBOX_WITH_NETFLT)
5453 /*
5454 * This is the new VBoxNetFlt+IntNet stuff.
5455 */
5456 Bstr BridgedIfName;
5457 hrc = aNetworkAdapter->COMGETTER(BridgedInterface)(BridgedIfName.asOutParam());
5458 if (FAILED(hrc))
5459 {
5460 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(BridgedInterface) failed, hrc (0x%x)\n", hrc));
5461 H();
5462 }
5463
5464 Utf8Str BridgedIfNameUtf8(BridgedIfName);
5465 const char *pszBridgedIfName = BridgedIfNameUtf8.c_str();
5466
5467 ComPtr<IHostNetworkInterface> hostInterface;
5468 hrc = host->FindHostNetworkInterfaceByName(BridgedIfName.raw(),
5469 hostInterface.asOutParam());
5470 if (!SUCCEEDED(hrc))
5471 {
5472 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: FindByName failed, rc=%Rhrc (0x%x)", hrc, hrc));
5473 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5474 N_("Nonexistent host networking interface, name '%ls'"),
5475 BridgedIfName.raw());
5476 }
5477
5478# if defined(RT_OS_DARWIN)
5479 /* The name is on the form 'ifX: long name', chop it off at the colon. */
5480 char szTrunk[INTNET_MAX_TRUNK_NAME];
5481 RTStrCopy(szTrunk, sizeof(szTrunk), pszBridgedIfName);
5482 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
5483// Quick fix for @bugref{5633}
5484// if (!pszColon)
5485// {
5486// /*
5487// * Dynamic changing of attachment causes an attempt to configure
5488// * network with invalid host adapter (as it is must be changed before
5489// * the attachment), calling Detach here will cause a deadlock.
5490// * See @bugref{4750}.
5491// * hrc = aNetworkAdapter->Detach(); H();
5492// */
5493// return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5494// N_("Malformed host interface networking name '%ls'"),
5495// BridgedIfName.raw());
5496// }
5497 if (pszColon)
5498 *pszColon = '\0';
5499 const char *pszTrunk = szTrunk;
5500
5501# elif defined(RT_OS_SOLARIS)
5502 /* The name is on the form format 'ifX[:1] - long name, chop it off at space. */
5503 char szTrunk[256];
5504 strlcpy(szTrunk, pszBridgedIfName, sizeof(szTrunk));
5505 char *pszSpace = (char *)memchr(szTrunk, ' ', sizeof(szTrunk));
5506
5507 /*
5508 * Currently don't bother about malformed names here for the sake of people using
5509 * VBoxManage and setting only the NIC name from there. If there is a space we
5510 * chop it off and proceed, otherwise just use whatever we've got.
5511 */
5512 if (pszSpace)
5513 *pszSpace = '\0';
5514
5515 /* Chop it off at the colon (zone naming eg: e1000g:1 we need only the e1000g) */
5516 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
5517 if (pszColon)
5518 *pszColon = '\0';
5519
5520 const char *pszTrunk = szTrunk;
5521
5522# elif defined(RT_OS_WINDOWS)
5523 HostNetworkInterfaceType_T eIfType;
5524 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
5525 if (FAILED(hrc))
5526 {
5527 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
5528 H();
5529 }
5530
5531 if (eIfType != HostNetworkInterfaceType_Bridged)
5532 {
5533 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5534 N_("Interface ('%ls') is not a Bridged Adapter interface"),
5535 BridgedIfName.raw());
5536 }
5537
5538 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
5539 if (FAILED(hrc))
5540 {
5541 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
5542 H();
5543 }
5544 Guid hostIFGuid(bstr);
5545
5546 INetCfg *pNc;
5547 ComPtr<INetCfgComponent> pAdaptorComponent;
5548 LPWSTR pszApp;
5549
5550 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
5551 Assert(hrc == S_OK);
5552 if (hrc != S_OK)
5553 {
5554 LogRel(("NetworkAttachmentType_Bridged: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5555 H();
5556 }
5557
5558 /* get the adapter's INetCfgComponent*/
5559 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
5560 pAdaptorComponent.asOutParam());
5561 if (hrc != S_OK)
5562 {
5563 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5564 LogRel(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)\n", hrc));
5565 H();
5566 }
5567# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
5568 char szTrunkName[INTNET_MAX_TRUNK_NAME];
5569 char *pszTrunkName = szTrunkName;
5570 wchar_t * pswzBindName;
5571 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
5572 Assert(hrc == S_OK);
5573 if (hrc == S_OK)
5574 {
5575 int cwBindName = (int)wcslen(pswzBindName) + 1;
5576 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
5577 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
5578 {
5579 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
5580 pszTrunkName += cbFullBindNamePrefix-1;
5581 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
5582 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
5583 {
5584 DWORD err = GetLastError();
5585 hrc = HRESULT_FROM_WIN32(err);
5586 AssertMsgFailed(("hrc=%Rhrc %#x\n", hrc, hrc));
5587 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
5588 hrc, hrc, err));
5589 }
5590 }
5591 else
5592 {
5593 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: insufficient szTrunkName buffer space\n"));
5594 /** @todo set appropriate error code */
5595 hrc = E_FAIL;
5596 }
5597
5598 if (hrc != S_OK)
5599 {
5600 AssertFailed();
5601 CoTaskMemFree(pswzBindName);
5602 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5603 H();
5604 }
5605
5606 /* we're not freeing the bind name since we'll use it later for detecting wireless*/
5607 }
5608 else
5609 {
5610 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5611 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)",
5612 hrc));
5613 H();
5614 }
5615
5616 const char *pszTrunk = szTrunkName;
5617 /* we're not releasing the INetCfg stuff here since we use it later to figure out whether it is wireless */
5618
5619# elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
5620# if defined(RT_OS_FREEBSD)
5621 /*
5622 * If we bridge to a tap interface open it the `old' direct way.
5623 * This works and performs better than bridging a physical
5624 * interface via the current FreeBSD vboxnetflt implementation.
5625 */
5626 if (!strncmp(pszBridgedIfName, RT_STR_TUPLE("tap"))) {
5627 hrc = i_attachToTapInterface(aNetworkAdapter);
5628 if (FAILED(hrc))
5629 {
5630 switch (hrc)
5631 {
5632 case E_ACCESSDENIED:
5633 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5634 "Failed to open '/dev/%s' for read/write access. Please check the "
5635 "permissions of that node, and that the net.link.tap.user_open "
5636 "sysctl is set. Either run 'chmod 0666 /dev/%s' or "
5637 "change the group of that node to vboxusers and make yourself "
5638 "a member of that group. Make sure that these changes are permanent."),
5639 pszBridgedIfName, pszBridgedIfName);
5640 default:
5641 AssertMsgFailed(("Could not attach to tap interface! Bad!\n"));
5642 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5643 "Failed to initialize Host Interface Networking"));
5644 }
5645 }
5646
5647 Assert((intptr_t)maTapFD[uInstance] >= 0);
5648 if ((intptr_t)maTapFD[uInstance] >= 0)
5649 {
5650 InsertConfigString(pLunL0, "Driver", "HostInterface");
5651 InsertConfigNode(pLunL0, "Config", &pCfg);
5652 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
5653 }
5654 break;
5655 }
5656# endif
5657 /** @todo Check for malformed names. */
5658 const char *pszTrunk = pszBridgedIfName;
5659
5660 /* Issue a warning if the interface is down */
5661 {
5662 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
5663 if (iSock >= 0)
5664 {
5665 struct ifreq Req;
5666 RT_ZERO(Req);
5667 RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pszBridgedIfName);
5668 if (ioctl(iSock, SIOCGIFFLAGS, &Req) >= 0)
5669 if ((Req.ifr_flags & IFF_UP) == 0)
5670 i_atVMRuntimeErrorCallbackF(0, "BridgedInterfaceDown",
5671 N_("Bridged interface %s is down. Guest will not be able to use this interface"),
5672 pszBridgedIfName);
5673
5674 close(iSock);
5675 }
5676 }
5677
5678# else
5679# error "PORTME (VBOX_WITH_NETFLT)"
5680# endif
5681
5682 InsertConfigString(pLunL0, "Driver", "IntNet");
5683 InsertConfigNode(pLunL0, "Config", &pCfg);
5684 InsertConfigString(pCfg, "Trunk", pszTrunk);
5685 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
5686 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure);
5687 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5688 char szNetwork[INTNET_MAX_NETWORK_NAME];
5689
5690# if defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN)
5691 /*
5692 * 'pszTrunk' contains just the interface name required in ring-0, while 'pszBridgedIfName' contains
5693 * interface name + optional description. We must not pass any description to the VM as it can differ
5694 * for the same interface name, eg: "nge0 - ethernet" (GUI) vs "nge0" (VBoxManage).
5695 */
5696 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszTrunk);
5697# else
5698 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszBridgedIfName);
5699# endif
5700 InsertConfigString(pCfg, "Network", szNetwork);
5701 networkName = Bstr(szNetwork);
5702 trunkName = Bstr(pszTrunk);
5703 trunkType = Bstr(TRUNKTYPE_NETFLT);
5704
5705 BOOL fSharedMacOnWire = false;
5706 hrc = hostInterface->COMGETTER(Wireless)(&fSharedMacOnWire);
5707 if (FAILED(hrc))
5708 {
5709 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Wireless) failed, hrc (0x%x)\n", hrc));
5710 H();
5711 }
5712 else if (fSharedMacOnWire)
5713 {
5714 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5715 Log(("Set SharedMacOnWire\n"));
5716 }
5717
5718# if defined(RT_OS_SOLARIS)
5719# if 0 /* bird: this is a bit questionable and might cause more trouble than its worth. */
5720 /* Zone access restriction, don't allow snooping the global zone. */
5721 zoneid_t ZoneId = getzoneid();
5722 if (ZoneId != GLOBAL_ZONEID)
5723 {
5724 InsertConfigInteger(pCfg, "IgnoreAllPromisc", true);
5725 }
5726# endif
5727# endif
5728
5729#elif defined(RT_OS_WINDOWS) /* not defined NetFlt */
5730 /* NOTHING TO DO HERE */
5731#elif defined(RT_OS_LINUX)
5732/// @todo aleksey: is there anything to be done here?
5733#elif defined(RT_OS_FREEBSD)
5734/** @todo FreeBSD: Check out this later (HIF networking). */
5735#else
5736# error "Port me"
5737#endif
5738 break;
5739 }
5740
5741 case NetworkAttachmentType_Internal:
5742 {
5743 hrc = aNetworkAdapter->COMGETTER(InternalNetwork)(bstr.asOutParam()); H();
5744 if (!bstr.isEmpty())
5745 {
5746 InsertConfigString(pLunL0, "Driver", "IntNet");
5747 InsertConfigNode(pLunL0, "Config", &pCfg);
5748 InsertConfigString(pCfg, "Network", bstr);
5749 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
5750 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5751 networkName = bstr;
5752 trunkType = Bstr(TRUNKTYPE_WHATEVER);
5753 }
5754 break;
5755 }
5756
5757 case NetworkAttachmentType_HostOnly:
5758 {
5759 InsertConfigString(pLunL0, "Driver", "IntNet");
5760 InsertConfigNode(pLunL0, "Config", &pCfg);
5761
5762 Bstr HostOnlyName;
5763 hrc = aNetworkAdapter->COMGETTER(HostOnlyInterface)(HostOnlyName.asOutParam());
5764 if (FAILED(hrc))
5765 {
5766 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(HostOnlyInterface) failed, hrc (0x%x)\n", hrc));
5767 H();
5768 }
5769
5770 Utf8Str HostOnlyNameUtf8(HostOnlyName);
5771 const char *pszHostOnlyName = HostOnlyNameUtf8.c_str();
5772 ComPtr<IHostNetworkInterface> hostInterface;
5773 rc = host->FindHostNetworkInterfaceByName(HostOnlyName.raw(),
5774 hostInterface.asOutParam());
5775 if (!SUCCEEDED(rc))
5776 {
5777 LogRel(("NetworkAttachmentType_HostOnly: FindByName failed, rc (0x%x)\n", rc));
5778 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5779 N_("Nonexistent host networking interface, name '%ls'"),
5780 HostOnlyName.raw());
5781 }
5782
5783 char szNetwork[INTNET_MAX_NETWORK_NAME];
5784 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszHostOnlyName);
5785
5786#if defined(RT_OS_WINDOWS)
5787# ifndef VBOX_WITH_NETFLT
5788 hrc = E_NOTIMPL;
5789 LogRel(("NetworkAttachmentType_HostOnly: Not Implemented\n"));
5790 H();
5791# else /* defined VBOX_WITH_NETFLT*/
5792 /** @todo r=bird: Put this in a function. */
5793
5794 HostNetworkInterfaceType_T eIfType;
5795 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
5796 if (FAILED(hrc))
5797 {
5798 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
5799 H();
5800 }
5801
5802 if (eIfType != HostNetworkInterfaceType_HostOnly)
5803 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5804 N_("Interface ('%ls') is not a Host-Only Adapter interface"),
5805 HostOnlyName.raw());
5806
5807 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
5808 if (FAILED(hrc))
5809 {
5810 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
5811 H();
5812 }
5813 Guid hostIFGuid(bstr);
5814
5815 INetCfg *pNc;
5816 ComPtr<INetCfgComponent> pAdaptorComponent;
5817 LPWSTR pszApp;
5818 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
5819 Assert(hrc == S_OK);
5820 if (hrc != S_OK)
5821 {
5822 LogRel(("NetworkAttachmentType_HostOnly: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5823 H();
5824 }
5825
5826 /* get the adapter's INetCfgComponent*/
5827 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
5828 pAdaptorComponent.asOutParam());
5829 if (hrc != S_OK)
5830 {
5831 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5832 LogRel(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5833 H();
5834 }
5835# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
5836 char szTrunkName[INTNET_MAX_TRUNK_NAME];
5837 bool fNdis6 = false;
5838 wchar_t * pwszHelpText;
5839 hrc = pAdaptorComponent->GetHelpText(&pwszHelpText);
5840 Assert(hrc == S_OK);
5841 if (hrc == S_OK)
5842 {
5843 Log(("help-text=%ls\n", pwszHelpText));
5844 if (!wcscmp(pwszHelpText, L"VirtualBox NDIS 6.0 Miniport Driver"))
5845 fNdis6 = true;
5846 CoTaskMemFree(pwszHelpText);
5847 }
5848 if (fNdis6)
5849 {
5850 strncpy(szTrunkName, pszHostOnlyName, sizeof(szTrunkName) - 1);
5851 Log(("trunk=%s\n", szTrunkName));
5852 }
5853 else
5854 {
5855 char *pszTrunkName = szTrunkName;
5856 wchar_t * pswzBindName;
5857 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
5858 Assert(hrc == S_OK);
5859 if (hrc == S_OK)
5860 {
5861 int cwBindName = (int)wcslen(pswzBindName) + 1;
5862 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
5863 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
5864 {
5865 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
5866 pszTrunkName += cbFullBindNamePrefix-1;
5867 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
5868 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
5869 {
5870 DWORD err = GetLastError();
5871 hrc = HRESULT_FROM_WIN32(err);
5872 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
5873 hrc, hrc, err));
5874 }
5875 }
5876 else
5877 {
5878 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: insufficient szTrunkName buffer space\n"));
5879 /** @todo set appropriate error code */
5880 hrc = E_FAIL;
5881 }
5882
5883 if (hrc != S_OK)
5884 {
5885 AssertFailed();
5886 CoTaskMemFree(pswzBindName);
5887 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5888 H();
5889 }
5890 }
5891 else
5892 {
5893 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5894 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n",
5895 hrc, hrc));
5896 H();
5897 }
5898
5899
5900 CoTaskMemFree(pswzBindName);
5901 }
5902
5903 trunkType = TRUNKTYPE_NETADP;
5904 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
5905
5906 pAdaptorComponent.setNull();
5907 /* release the pNc finally */
5908 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5909
5910 const char *pszTrunk = szTrunkName;
5911
5912 InsertConfigString(pCfg, "Trunk", pszTrunk);
5913 InsertConfigString(pCfg, "Network", szNetwork);
5914 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure); /** @todo why is this
5915 windows only?? */
5916 networkName = Bstr(szNetwork);
5917 trunkName = Bstr(pszTrunk);
5918# endif /* defined VBOX_WITH_NETFLT*/
5919#elif defined(RT_OS_DARWIN)
5920 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
5921 InsertConfigString(pCfg, "Network", szNetwork);
5922 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
5923 networkName = Bstr(szNetwork);
5924 trunkName = Bstr(pszHostOnlyName);
5925 trunkType = TRUNKTYPE_NETADP;
5926#else
5927 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
5928 InsertConfigString(pCfg, "Network", szNetwork);
5929 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
5930 networkName = Bstr(szNetwork);
5931 trunkName = Bstr(pszHostOnlyName);
5932 trunkType = TRUNKTYPE_NETFLT;
5933#endif
5934 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5935
5936#if !defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
5937
5938 Bstr tmpAddr, tmpMask;
5939
5940 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPAddress",
5941 pszHostOnlyName).raw(),
5942 tmpAddr.asOutParam());
5943 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty())
5944 {
5945 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPNetMask",
5946 pszHostOnlyName).raw(),
5947 tmpMask.asOutParam());
5948 if (SUCCEEDED(hrc) && !tmpMask.isEmpty())
5949 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
5950 tmpMask.raw());
5951 else
5952 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
5953 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
5954 }
5955 else
5956 {
5957 /* Grab the IP number from the 'vboxnetX' instance number (see netif.h) */
5958 hrc = hostInterface->EnableStaticIPConfig(getDefaultIPv4Address(Bstr(pszHostOnlyName)).raw(),
5959 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
5960 }
5961
5962 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
5963
5964 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6Address",
5965 pszHostOnlyName).raw(),
5966 tmpAddr.asOutParam());
5967 if (SUCCEEDED(hrc))
5968 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6NetMask", pszHostOnlyName).raw(),
5969 tmpMask.asOutParam());
5970 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty() && !tmpMask.isEmpty())
5971 {
5972 hrc = hostInterface->EnableStaticIPConfigV6(tmpAddr.raw(),
5973 Utf8Str(tmpMask).toUInt32());
5974 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
5975 }
5976#endif
5977 break;
5978 }
5979
5980 case NetworkAttachmentType_Generic:
5981 {
5982 hrc = aNetworkAdapter->COMGETTER(GenericDriver)(bstr.asOutParam()); H();
5983 SafeArray<BSTR> names;
5984 SafeArray<BSTR> values;
5985 hrc = aNetworkAdapter->GetProperties(Bstr().raw(),
5986 ComSafeArrayAsOutParam(names),
5987 ComSafeArrayAsOutParam(values)); H();
5988
5989 InsertConfigString(pLunL0, "Driver", bstr);
5990 InsertConfigNode(pLunL0, "Config", &pCfg);
5991 for (size_t ii = 0; ii < names.size(); ++ii)
5992 {
5993 if (values[ii] && *values[ii])
5994 {
5995 Utf8Str name = names[ii];
5996 Utf8Str value = values[ii];
5997 InsertConfigString(pCfg, name.c_str(), value);
5998 }
5999 }
6000 break;
6001 }
6002
6003 case NetworkAttachmentType_NATNetwork:
6004 {
6005 hrc = aNetworkAdapter->COMGETTER(NATNetwork)(bstr.asOutParam()); H();
6006 if (!bstr.isEmpty())
6007 {
6008 /** @todo add intnet prefix to separate namespaces, and add trunk if dealing with vboxnatX */
6009 InsertConfigString(pLunL0, "Driver", "IntNet");
6010 InsertConfigNode(pLunL0, "Config", &pCfg);
6011 InsertConfigString(pCfg, "Network", bstr);
6012 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
6013 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
6014 networkName = bstr;
6015 trunkType = Bstr(TRUNKTYPE_WHATEVER);
6016 }
6017 break;
6018 }
6019
6020#ifdef VBOX_WITH_CLOUD_NET
6021 case NetworkAttachmentType_Cloud:
6022 {
6023 static const char *s_pszCloudExtPackName = "Oracle VM VirtualBox Extension Pack";
6024 /*
6025 * Cloud network attachments do not work wihout installed extpack.
6026 * Without extpack support they won't work either.
6027 */
6028# ifdef VBOX_WITH_EXTPACK
6029 if (!mptrExtPackManager->i_isExtPackUsable(s_pszCloudExtPackName))
6030# endif
6031 {
6032 return VMSetError(VMR3GetVM(mpUVM), VERR_NOT_FOUND, RT_SRC_POS,
6033 N_("Implementation of the cloud network attachment not found!\n"
6034 "To fix this problem, either install the '%s' or switch to "
6035 "another network attachment type in the VM settings.\n"
6036 ),
6037 s_pszCloudExtPackName);
6038 }
6039
6040 ComPtr<ICloudNetwork> network;
6041 hrc = aNetworkAdapter->COMGETTER(CloudNetwork)(bstr.asOutParam()); H();
6042 hrc = pMachine->COMGETTER(Name)(mGateways.mTargetVM.asOutParam()); H();
6043 hrc = virtualBox->FindCloudNetworkByName(bstr.raw(), network.asOutParam()); H();
6044 hrc = startGateways(virtualBox, network, mGateways); H();
6045 InsertConfigBytes(pDevCfg, "MAC", &mGateways.mCloudMacAddress, sizeof(mGateways.mCloudMacAddress));
6046 if (!bstr.isEmpty())
6047 {
6048 InsertConfigString(pLunL0, "Driver", "IntNet");
6049 InsertConfigNode(pLunL0, "Config", &pCfg);
6050 InsertConfigString(pCfg, "Network", BstrFmt("cloud-%ls", bstr.raw()));
6051 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
6052 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
6053 networkName = bstr;
6054 trunkType = Bstr(TRUNKTYPE_WHATEVER);
6055 }
6056 break;
6057 }
6058#endif /* VBOX_WITH_CLOUD_NET */
6059
6060 default:
6061 AssertMsgFailed(("should not get here!\n"));
6062 break;
6063 }
6064
6065 /*
6066 * Attempt to attach the driver.
6067 */
6068 switch (eAttachmentType)
6069 {
6070 case NetworkAttachmentType_Null:
6071 break;
6072
6073 case NetworkAttachmentType_Bridged:
6074 case NetworkAttachmentType_Internal:
6075 case NetworkAttachmentType_HostOnly:
6076 case NetworkAttachmentType_NAT:
6077 case NetworkAttachmentType_Generic:
6078 case NetworkAttachmentType_NATNetwork:
6079#ifdef VBOX_WITH_CLOUD_NET
6080 case NetworkAttachmentType_Cloud:
6081#endif /* VBOX_WITH_CLOUD_NET */
6082 {
6083 if (SUCCEEDED(hrc) && RT_SUCCESS(rc))
6084 {
6085 if (fAttachDetach)
6086 {
6087 rc = PDMR3DriverAttach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/, NULL /* ppBase */);
6088 //AssertRC(rc);
6089 }
6090
6091 {
6092 /** @todo pritesh: get the dhcp server name from the
6093 * previous network configuration and then stop the server
6094 * else it may conflict with the dhcp server running with
6095 * the current attachment type
6096 */
6097 /* Stop the hostonly DHCP Server */
6098 }
6099
6100 /*
6101 * NAT networks start their DHCP server theirself, see NATNetwork::Start()
6102 */
6103 if ( !networkName.isEmpty()
6104 && eAttachmentType != NetworkAttachmentType_NATNetwork)
6105 {
6106 /*
6107 * Until we implement service reference counters DHCP Server will be stopped
6108 * by DHCPServerRunner destructor.
6109 */
6110 ComPtr<IDHCPServer> dhcpServer;
6111 hrc = virtualBox->FindDHCPServerByNetworkName(networkName.raw(),
6112 dhcpServer.asOutParam());
6113 if (SUCCEEDED(hrc))
6114 {
6115 /* there is a DHCP server available for this network */
6116 BOOL fEnabledDhcp;
6117 hrc = dhcpServer->COMGETTER(Enabled)(&fEnabledDhcp);
6118 if (FAILED(hrc))
6119 {
6120 LogRel(("DHCP svr: COMGETTER(Enabled) failed, hrc (%Rhrc)\n", hrc));
6121 H();
6122 }
6123
6124 if (fEnabledDhcp)
6125 hrc = dhcpServer->Start(trunkName.raw(),
6126 trunkType.raw());
6127 }
6128 else
6129 hrc = S_OK;
6130 }
6131 }
6132
6133 break;
6134 }
6135
6136 default:
6137 AssertMsgFailed(("should not get here!\n"));
6138 break;
6139 }
6140
6141 meAttachmentType[uInstance] = eAttachmentType;
6142 }
6143 catch (ConfigError &x)
6144 {
6145 // InsertConfig threw something:
6146 return x.m_vrc;
6147 }
6148
6149#undef H
6150
6151 return VINF_SUCCESS;
6152}
6153
6154
6155/**
6156 * Configures the serial port at the given CFGM node with the supplied parameters.
6157 *
6158 * @returns VBox status code.
6159 * @param pInst The instance CFGM node.
6160 * @param ePortMode The port mode to sue.
6161 * @param pszPath The serial port path.
6162 * @param fServer Flag whether the port should act as a server
6163 * for the pipe and TCP mode or connect as a client.
6164 */
6165int Console::i_configSerialPort(PCFGMNODE pInst, PortMode_T ePortMode, const char *pszPath, bool fServer)
6166{
6167 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
6168 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */
6169 PCFGMNODE pLunL1Cfg = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/Config */
6170
6171 try
6172 {
6173 InsertConfigNode(pInst, "LUN#0", &pLunL0);
6174 if (ePortMode == PortMode_HostPipe)
6175 {
6176 InsertConfigString(pLunL0, "Driver", "Char");
6177 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
6178 InsertConfigString(pLunL1, "Driver", "NamedPipe");
6179 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
6180 InsertConfigString(pLunL1Cfg, "Location", pszPath);
6181 InsertConfigInteger(pLunL1Cfg, "IsServer", fServer);
6182 }
6183 else if (ePortMode == PortMode_HostDevice)
6184 {
6185 InsertConfigString(pLunL0, "Driver", "Host Serial");
6186 InsertConfigNode(pLunL0, "Config", &pLunL1);
6187 InsertConfigString(pLunL1, "DevicePath", pszPath);
6188 }
6189 else if (ePortMode == PortMode_TCP)
6190 {
6191 InsertConfigString(pLunL0, "Driver", "Char");
6192 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
6193 InsertConfigString(pLunL1, "Driver", "TCP");
6194 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
6195 InsertConfigString(pLunL1Cfg, "Location", pszPath);
6196 InsertConfigInteger(pLunL1Cfg, "IsServer", fServer);
6197 }
6198 else if (ePortMode == PortMode_RawFile)
6199 {
6200 InsertConfigString(pLunL0, "Driver", "Char");
6201 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
6202 InsertConfigString(pLunL1, "Driver", "RawFile");
6203 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
6204 InsertConfigString(pLunL1Cfg, "Location", pszPath);
6205 }
6206 }
6207 catch (ConfigError &x)
6208 {
6209 /* InsertConfig threw something */
6210 return x.m_vrc;
6211 }
6212
6213 return VINF_SUCCESS;
6214}
6215
Note: See TracBrowser for help on using the repository browser.

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