VirtualBox

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

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

Main/VBoxC: Fix Medium::parent reference leaks in Console::i_configMedium(). bugref:9841

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

© 2023 Oracle
ContactPrivacy policyTerms of Use