VirtualBox

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

Last change on this file since 81883 was 81883, checked in by vboxsync, 5 years ago

Main/DHCPServer+NatNetwork+VirtualBox+Console: Remove old DHCP methods, attributes and interfaces, plus eliminate useless parameters from NATNetwork and DHCPServer Start methods. Additionally a few fixes to the DTD (and correcting some XML goofs in VirtualBox.xidl). More reserved attributes for the not yet implemented ICloudNetwork.

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

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