VirtualBox

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

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

Main/GraphicsAdapter: Split off a few attributes from Machine interface, which affects quite a few other interfaces.
Frontends/VirtualBox+VBoxManage+VBoxSDL+VBoxShell: Adapt accordingly.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 248.8 KB
Line 
1/* $Id: ConsoleImpl2.cpp 81964 2019-11-18 20:42:02Z 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 ComPtr<IGraphicsAdapter> pGraphicsAdapter;
1637 hrc = pMachine->COMGETTER(GraphicsAdapter)(pGraphicsAdapter.asOutParam()); H();
1638 GraphicsControllerType_T enmGraphicsController;
1639 hrc = pGraphicsAdapter->COMGETTER(GraphicsControllerType)(&enmGraphicsController); H();
1640 switch (enmGraphicsController)
1641 {
1642 case GraphicsControllerType_Null:
1643 break;
1644#ifdef VBOX_WITH_VMSVGA
1645 case GraphicsControllerType_VMSVGA:
1646 InsertConfigInteger(pHM, "LovelyMesaDrvWorkaround", 1); /* hits someone else logging backdoor. */
1647 RT_FALL_THROUGH();
1648 case GraphicsControllerType_VBoxSVGA:
1649#endif
1650 case GraphicsControllerType_VBoxVGA:
1651 rc = i_configGraphicsController(pDevices, enmGraphicsController, pBusMgr, pMachine, pGraphicsAdapter, biosSettings,
1652 RT_BOOL(fHMEnabled));
1653 if (FAILED(rc))
1654 return rc;
1655 break;
1656 default:
1657 AssertMsgFailed(("Invalid graphicsController=%d\n", enmGraphicsController));
1658 return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1659 N_("Invalid graphics controller type '%d'"), enmGraphicsController);
1660 }
1661
1662 /*
1663 * Firmware.
1664 */
1665 FirmwareType_T eFwType = FirmwareType_BIOS;
1666 hrc = pMachine->COMGETTER(FirmwareType)(&eFwType); H();
1667
1668#ifdef VBOX_WITH_EFI
1669 BOOL fEfiEnabled = (eFwType >= FirmwareType_EFI) && (eFwType <= FirmwareType_EFIDUAL);
1670#else
1671 BOOL fEfiEnabled = false;
1672#endif
1673 if (!fEfiEnabled)
1674 {
1675 /*
1676 * PC Bios.
1677 */
1678 InsertConfigNode(pDevices, "pcbios", &pDev);
1679 InsertConfigNode(pDev, "0", &pInst);
1680 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1681 InsertConfigNode(pInst, "Config", &pBiosCfg);
1682 InsertConfigInteger(pBiosCfg, "NumCPUs", cCpus);
1683 InsertConfigString(pBiosCfg, "HardDiskDevice", "piix3ide");
1684 InsertConfigString(pBiosCfg, "FloppyDevice", "i82078");
1685 InsertConfigInteger(pBiosCfg, "IOAPIC", fIOAPIC);
1686 InsertConfigInteger(pBiosCfg, "APIC", uFwAPIC);
1687 BOOL fPXEDebug;
1688 hrc = biosSettings->COMGETTER(PXEDebugEnabled)(&fPXEDebug); H();
1689 InsertConfigInteger(pBiosCfg, "PXEDebug", fPXEDebug);
1690 InsertConfigBytes(pBiosCfg, "UUID", &HardwareUuid,sizeof(HardwareUuid));
1691 BOOL fUuidLe;
1692 hrc = biosSettings->COMGETTER(SMBIOSUuidLittleEndian)(&fUuidLe); H();
1693 InsertConfigInteger(pBiosCfg, "UuidLe", fUuidLe);
1694 InsertConfigNode(pBiosCfg, "NetBoot", &pNetBootCfg);
1695 InsertConfigInteger(pBiosCfg, "McfgBase", uMcfgBase);
1696 InsertConfigInteger(pBiosCfg, "McfgLength", cbMcfgLength);
1697
1698 DeviceType_T bootDevice;
1699 AssertMsgReturn(SchemaDefs::MaxBootPosition <= 9, ("Too many boot devices %d\n", SchemaDefs::MaxBootPosition),
1700 VERR_INVALID_PARAMETER);
1701
1702 for (ULONG pos = 1; pos <= SchemaDefs::MaxBootPosition; ++pos)
1703 {
1704 hrc = pMachine->GetBootOrder(pos, &bootDevice); H();
1705
1706 char szParamName[] = "BootDeviceX";
1707 szParamName[sizeof(szParamName) - 2] = (char)(pos - 1 + '0');
1708
1709 const char *pszBootDevice;
1710 switch (bootDevice)
1711 {
1712 case DeviceType_Null:
1713 pszBootDevice = "NONE";
1714 break;
1715 case DeviceType_HardDisk:
1716 pszBootDevice = "IDE";
1717 break;
1718 case DeviceType_DVD:
1719 pszBootDevice = "DVD";
1720 break;
1721 case DeviceType_Floppy:
1722 pszBootDevice = "FLOPPY";
1723 break;
1724 case DeviceType_Network:
1725 pszBootDevice = "LAN";
1726 break;
1727 default:
1728 AssertMsgFailed(("Invalid bootDevice=%d\n", bootDevice));
1729 return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1730 N_("Invalid boot device '%d'"), bootDevice);
1731 }
1732 InsertConfigString(pBiosCfg, szParamName, pszBootDevice);
1733 }
1734
1735 /** @todo @bugref{7145}: We might want to enable this by default for new VMs. For now,
1736 * this is required for Windows 2012 guests. */
1737 if (osTypeId == "Windows2012_64")
1738 InsertConfigInteger(pBiosCfg, "DmiExposeMemoryTable", 1); /* boolean */
1739 }
1740 else
1741 {
1742 /* Autodetect firmware type, basing on guest type */
1743 if (eFwType == FirmwareType_EFI)
1744 eFwType = fIsGuest64Bit ? FirmwareType_EFI64 : FirmwareType_EFI32;
1745 bool const f64BitEntry = eFwType == FirmwareType_EFI64;
1746
1747 Assert(eFwType == FirmwareType_EFI64 || eFwType == FirmwareType_EFI32 || eFwType == FirmwareType_EFIDUAL);
1748#ifdef VBOX_WITH_EFI_IN_DD2
1749 const char *pszEfiRomFile = eFwType == FirmwareType_EFIDUAL ? "VBoxEFIDual.fd"
1750 : eFwType == FirmwareType_EFI32 ? "VBoxEFI32.fd"
1751 : "VBoxEFI64.fd";
1752#else
1753 Utf8Str efiRomFile;
1754 rc = findEfiRom(virtualBox, eFwType, &efiRomFile);
1755 AssertRCReturn(rc, rc);
1756 const char *pszEfiRomFile = efiRomFile.c_str();
1757#endif
1758
1759 /* Get boot args */
1760 Utf8Str bootArgs;
1761 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiBootArgs", &bootArgs);
1762
1763 /* Get device props */
1764 Utf8Str deviceProps;
1765 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiDeviceProps", &deviceProps);
1766
1767 /* Get NVRAM file name */
1768 Bstr bstrNVRAM;
1769 hrc = biosSettings->COMGETTER(NonVolatileStorageFile)(bstrNVRAM.asOutParam()); H();
1770
1771 BOOL fUuidLe;
1772 hrc = biosSettings->COMGETTER(SMBIOSUuidLittleEndian)(&fUuidLe); H();
1773
1774 /* Get graphics mode settings */
1775 uint32_t u32GraphicsMode = UINT32_MAX;
1776 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGraphicsMode", &strTmp);
1777 if (strTmp.isEmpty())
1778 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGopMode", &strTmp);
1779 if (!strTmp.isEmpty())
1780 u32GraphicsMode = strTmp.toUInt32();
1781
1782 /* Get graphics resolution settings, with some sanity checking */
1783 Utf8Str strResolution;
1784 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGraphicsResolution", &strResolution);
1785 if (!strResolution.isEmpty())
1786 {
1787 size_t pos = strResolution.find("x");
1788 if (pos != strResolution.npos)
1789 {
1790 Utf8Str strH, strV;
1791 strH.assignEx(strResolution, 0, pos);
1792 strV.assignEx(strResolution, pos+1, strResolution.length()-pos-1);
1793 uint32_t u32H = strH.toUInt32();
1794 uint32_t u32V = strV.toUInt32();
1795 if (u32H == 0 || u32V == 0)
1796 strResolution.setNull();
1797 }
1798 else
1799 strResolution.setNull();
1800 }
1801 else
1802 {
1803 uint32_t u32H = 0;
1804 uint32_t u32V = 0;
1805 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiHorizontalResolution", &strTmp);
1806 if (strTmp.isEmpty())
1807 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiUgaHorizontalResolution", &strTmp);
1808 if (!strTmp.isEmpty())
1809 u32H = strTmp.toUInt32();
1810
1811 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiVerticalResolution", &strTmp);
1812 if (strTmp.isEmpty())
1813 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiUgaVerticalResolution", &strTmp);
1814 if (!strTmp.isEmpty())
1815 u32V = strTmp.toUInt32();
1816 if (u32H != 0 && u32V != 0)
1817 strResolution = Utf8StrFmt("%ux%u", u32H, u32V);
1818 }
1819
1820 /*
1821 * EFI subtree.
1822 */
1823 InsertConfigNode(pDevices, "efi", &pDev);
1824 InsertConfigNode(pDev, "0", &pInst);
1825 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1826 InsertConfigNode(pInst, "Config", &pCfg);
1827 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1828 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
1829 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
1830 InsertConfigString(pCfg, "EfiRom", pszEfiRomFile);
1831 InsertConfigString(pCfg, "BootArgs", bootArgs);
1832 InsertConfigString(pCfg, "DeviceProps", deviceProps);
1833 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1834 InsertConfigInteger(pCfg, "APIC", uFwAPIC);
1835 InsertConfigBytes(pCfg, "UUID", &HardwareUuid,sizeof(HardwareUuid));
1836 InsertConfigInteger(pCfg, "UuidLe", fUuidLe);
1837 InsertConfigInteger(pCfg, "64BitEntry", f64BitEntry); /* boolean */
1838 InsertConfigString(pCfg, "NvramFile", bstrNVRAM);
1839 if (u32GraphicsMode != UINT32_MAX)
1840 InsertConfigInteger(pCfg, "GraphicsMode", u32GraphicsMode);
1841 if (!strResolution.isEmpty())
1842 InsertConfigString(pCfg, "GraphicsResolution", strResolution);
1843
1844 /* For OS X guests we'll force passing host's DMI info to the guest */
1845 if (fOsXGuest)
1846 {
1847 InsertConfigInteger(pCfg, "DmiUseHostInfo", 1);
1848 InsertConfigInteger(pCfg, "DmiExposeMemoryTable", 1);
1849 }
1850 }
1851
1852 /*
1853 * The USB Controllers.
1854 */
1855 com::SafeIfaceArray<IUSBController> usbCtrls;
1856 hrc = pMachine->COMGETTER(USBControllers)(ComSafeArrayAsOutParam(usbCtrls));
1857 bool fOhciPresent = false; /**< Flag whether at least one OHCI controller is present. */
1858 bool fXhciPresent = false; /**< Flag whether at least one XHCI controller is present. */
1859
1860 if (SUCCEEDED(hrc))
1861 {
1862 for (size_t i = 0; i < usbCtrls.size(); ++i)
1863 {
1864 USBControllerType_T enmCtrlType;
1865 rc = usbCtrls[i]->COMGETTER(Type)(&enmCtrlType); H();
1866 if (enmCtrlType == USBControllerType_OHCI)
1867 {
1868 fOhciPresent = true;
1869 break;
1870 }
1871 else if (enmCtrlType == USBControllerType_XHCI)
1872 {
1873 fXhciPresent = true;
1874 break;
1875 }
1876 }
1877 }
1878 else if (hrc != E_NOTIMPL)
1879 {
1880 H();
1881 }
1882
1883 /*
1884 * Currently EHCI is only enabled when an OHCI or XHCI controller is present as well.
1885 */
1886 if (fOhciPresent || fXhciPresent)
1887 mfVMHasUsbController = true;
1888
1889 PCFGMNODE pUsbDevices = NULL; /**< Required for USB storage controller later. */
1890 if (mfVMHasUsbController)
1891 {
1892 for (size_t i = 0; i < usbCtrls.size(); ++i)
1893 {
1894 USBControllerType_T enmCtrlType;
1895 rc = usbCtrls[i]->COMGETTER(Type)(&enmCtrlType); H();
1896
1897 if (enmCtrlType == USBControllerType_OHCI)
1898 {
1899 InsertConfigNode(pDevices, "usb-ohci", &pDev);
1900 InsertConfigNode(pDev, "0", &pInst);
1901 InsertConfigNode(pInst, "Config", &pCfg);
1902 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1903 hrc = pBusMgr->assignPCIDevice("usb-ohci", pInst); H();
1904 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1905 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
1906 InsertConfigNode(pLunL0, "Config", &pCfg);
1907
1908 /*
1909 * Attach the status driver.
1910 */
1911 i_attachStatusDriver(pInst, &mapUSBLed[0], 0, 0, NULL, NULL, 0);
1912 }
1913#ifdef VBOX_WITH_EHCI
1914 else if (enmCtrlType == USBControllerType_EHCI)
1915 {
1916 /*
1917 * USB 2.0 is only available if the proper ExtPack is installed.
1918 *
1919 * Note. Configuring EHCI here and providing messages about
1920 * the missing extpack isn't exactly clean, but it is a
1921 * necessary evil to patch over legacy compatability issues
1922 * introduced by the new distribution model.
1923 */
1924# ifdef VBOX_WITH_EXTPACK
1925 static const char *s_pszUsbExtPackName = "Oracle VM VirtualBox Extension Pack";
1926 if (mptrExtPackManager->i_isExtPackUsable(s_pszUsbExtPackName))
1927# endif
1928 {
1929 InsertConfigNode(pDevices, "usb-ehci", &pDev);
1930 InsertConfigNode(pDev, "0", &pInst);
1931 InsertConfigNode(pInst, "Config", &pCfg);
1932 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1933 hrc = pBusMgr->assignPCIDevice("usb-ehci", pInst); H();
1934
1935 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1936 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
1937 InsertConfigNode(pLunL0, "Config", &pCfg);
1938
1939 /*
1940 * Attach the status driver.
1941 */
1942 i_attachStatusDriver(pInst, &mapUSBLed[1], 0, 0, NULL, NULL, 0);
1943 }
1944# ifdef VBOX_WITH_EXTPACK
1945 else
1946 {
1947 /* Always fatal! Up to VBox 4.0.4 we allowed to start the VM anyway
1948 * but this induced problems when the user saved + restored the VM! */
1949 return VMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
1950 N_("Implementation of the USB 2.0 controller not found!\n"
1951 "Because the USB 2.0 controller state is part of the saved "
1952 "VM state, the VM cannot be started. To fix "
1953 "this problem, either install the '%s' or disable USB 2.0 "
1954 "support in the VM settings.\n"
1955 "Note! This error could also mean that an incompatible version of "
1956 "the '%s' is installed"),
1957 s_pszUsbExtPackName, s_pszUsbExtPackName);
1958 }
1959# endif
1960 }
1961#endif
1962 else if (enmCtrlType == USBControllerType_XHCI)
1963 {
1964 /*
1965 * USB 3.0 is only available if the proper ExtPack is installed.
1966 *
1967 * Note. Configuring EHCI here and providing messages about
1968 * the missing extpack isn't exactly clean, but it is a
1969 * necessary evil to patch over legacy compatability issues
1970 * introduced by the new distribution model.
1971 */
1972# ifdef VBOX_WITH_EXTPACK
1973 static const char *s_pszUsbExtPackName = "Oracle VM VirtualBox Extension Pack";
1974 if (mptrExtPackManager->i_isExtPackUsable(s_pszUsbExtPackName))
1975# endif
1976 {
1977 InsertConfigNode(pDevices, "usb-xhci", &pDev);
1978 InsertConfigNode(pDev, "0", &pInst);
1979 InsertConfigNode(pInst, "Config", &pCfg);
1980 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1981 hrc = pBusMgr->assignPCIDevice("usb-xhci", pInst); H();
1982
1983 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1984 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
1985 InsertConfigNode(pLunL0, "Config", &pCfg);
1986
1987 InsertConfigNode(pInst, "LUN#1", &pLunL1);
1988 InsertConfigString(pLunL1, "Driver", "VUSBRootHub");
1989 InsertConfigNode(pLunL1, "Config", &pCfg);
1990
1991 /*
1992 * Attach the status driver.
1993 */
1994 i_attachStatusDriver(pInst, &mapUSBLed[0], 0, 1, NULL, NULL, 0);
1995 }
1996# ifdef VBOX_WITH_EXTPACK
1997 else
1998 {
1999 /* Always fatal. */
2000 return VMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
2001 N_("Implementation of the USB 3.0 controller not found!\n"
2002 "Because the USB 3.0 controller state is part of the saved "
2003 "VM state, the VM cannot be started. To fix "
2004 "this problem, either install the '%s' or disable USB 3.0 "
2005 "support in the VM settings"),
2006 s_pszUsbExtPackName);
2007 }
2008# endif
2009 }
2010 } /* for every USB controller. */
2011
2012
2013 /*
2014 * Virtual USB Devices.
2015 */
2016 InsertConfigNode(pRoot, "USB", &pUsbDevices);
2017
2018#ifdef VBOX_WITH_USB
2019 {
2020 /*
2021 * Global USB options, currently unused as we'll apply the 2.0 -> 1.1 morphing
2022 * on a per device level now.
2023 */
2024 InsertConfigNode(pUsbDevices, "USBProxy", &pCfg);
2025 InsertConfigNode(pCfg, "GlobalConfig", &pCfg);
2026 // This globally enables the 2.0 -> 1.1 device morphing of proxied devices to keep windows quiet.
2027 //InsertConfigInteger(pCfg, "Force11Device", true);
2028 // The following breaks stuff, but it makes MSDs work in vista. (I include it here so
2029 // that it's documented somewhere.) Users needing it can use:
2030 // VBoxManage setextradata "myvm" "VBoxInternal/USB/USBProxy/GlobalConfig/Force11PacketSize" 1
2031 //InsertConfigInteger(pCfg, "Force11PacketSize", true);
2032 }
2033#endif
2034
2035#ifdef VBOX_WITH_USB_CARDREADER
2036 BOOL aEmulatedUSBCardReaderEnabled = FALSE;
2037 hrc = pMachine->COMGETTER(EmulatedUSBCardReaderEnabled)(&aEmulatedUSBCardReaderEnabled); H();
2038 if (aEmulatedUSBCardReaderEnabled)
2039 {
2040 InsertConfigNode(pUsbDevices, "CardReader", &pDev);
2041 InsertConfigNode(pDev, "0", &pInst);
2042 InsertConfigNode(pInst, "Config", &pCfg);
2043
2044 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2045# ifdef VBOX_WITH_USB_CARDREADER_TEST
2046 InsertConfigString(pLunL0, "Driver", "DrvDirectCardReader");
2047 InsertConfigNode(pLunL0, "Config", &pCfg);
2048# else
2049 InsertConfigString(pLunL0, "Driver", "UsbCardReader");
2050 InsertConfigNode(pLunL0, "Config", &pCfg);
2051 InsertConfigInteger(pCfg, "Object", (uintptr_t)mUsbCardReader);
2052# endif
2053 }
2054#endif
2055
2056 /* Virtual USB Mouse/Tablet */
2057 if ( aPointingHID == PointingHIDType_USBMouse
2058 || aPointingHID == PointingHIDType_USBTablet
2059 || aPointingHID == PointingHIDType_USBMultiTouch)
2060 {
2061 InsertConfigNode(pUsbDevices, "HidMouse", &pDev);
2062 InsertConfigNode(pDev, "0", &pInst);
2063 InsertConfigNode(pInst, "Config", &pCfg);
2064
2065 if (aPointingHID == PointingHIDType_USBMouse)
2066 InsertConfigString(pCfg, "Mode", "relative");
2067 else
2068 InsertConfigString(pCfg, "Mode", "absolute");
2069 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2070 InsertConfigString(pLunL0, "Driver", "MouseQueue");
2071 InsertConfigNode(pLunL0, "Config", &pCfg);
2072 InsertConfigInteger(pCfg, "QueueSize", 128);
2073
2074 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2075 InsertConfigString(pLunL1, "Driver", "MainMouse");
2076 InsertConfigNode(pLunL1, "Config", &pCfg);
2077 InsertConfigInteger(pCfg, "Object", (uintptr_t)pMouse);
2078 }
2079 if (aPointingHID == PointingHIDType_USBMultiTouch)
2080 {
2081 InsertConfigNode(pDev, "1", &pInst);
2082 InsertConfigNode(pInst, "Config", &pCfg);
2083
2084 InsertConfigString(pCfg, "Mode", "multitouch");
2085 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2086 InsertConfigString(pLunL0, "Driver", "MouseQueue");
2087 InsertConfigNode(pLunL0, "Config", &pCfg);
2088 InsertConfigInteger(pCfg, "QueueSize", 128);
2089
2090 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2091 InsertConfigString(pLunL1, "Driver", "MainMouse");
2092 InsertConfigNode(pLunL1, "Config", &pCfg);
2093 InsertConfigInteger(pCfg, "Object", (uintptr_t)pMouse);
2094 }
2095
2096 /* Virtual USB Keyboard */
2097 KeyboardHIDType_T aKbdHID;
2098 hrc = pMachine->COMGETTER(KeyboardHIDType)(&aKbdHID); H();
2099 if (aKbdHID == KeyboardHIDType_USBKeyboard)
2100 {
2101 InsertConfigNode(pUsbDevices, "HidKeyboard", &pDev);
2102 InsertConfigNode(pDev, "0", &pInst);
2103 InsertConfigNode(pInst, "Config", &pCfg);
2104
2105 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2106 InsertConfigString(pLunL0, "Driver", "KeyboardQueue");
2107 InsertConfigNode(pLunL0, "Config", &pCfg);
2108 InsertConfigInteger(pCfg, "QueueSize", 64);
2109
2110 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2111 InsertConfigString(pLunL1, "Driver", "MainKeyboard");
2112 InsertConfigNode(pLunL1, "Config", &pCfg);
2113 pKeyboard = mKeyboard;
2114 InsertConfigInteger(pCfg, "Object", (uintptr_t)pKeyboard);
2115 }
2116 }
2117
2118 /*
2119 * Storage controllers.
2120 */
2121 com::SafeIfaceArray<IStorageController> ctrls;
2122 PCFGMNODE aCtrlNodes[StorageControllerType_VirtioSCSI + 1] = {};
2123 hrc = pMachine->COMGETTER(StorageControllers)(ComSafeArrayAsOutParam(ctrls)); H();
2124
2125 bool fFdcEnabled = false;
2126 for (size_t i = 0; i < ctrls.size(); ++i)
2127 {
2128 DeviceType_T *paLedDevType = NULL;
2129
2130 StorageControllerType_T enmCtrlType;
2131 rc = ctrls[i]->COMGETTER(ControllerType)(&enmCtrlType); H();
2132 AssertRelease((unsigned)enmCtrlType < RT_ELEMENTS(aCtrlNodes)
2133 || enmCtrlType == StorageControllerType_USB);
2134
2135 StorageBus_T enmBus;
2136 rc = ctrls[i]->COMGETTER(Bus)(&enmBus); H();
2137
2138 Bstr controllerName;
2139 rc = ctrls[i]->COMGETTER(Name)(controllerName.asOutParam()); H();
2140
2141 ULONG ulInstance = 999;
2142 rc = ctrls[i]->COMGETTER(Instance)(&ulInstance); H();
2143
2144 BOOL fUseHostIOCache;
2145 rc = ctrls[i]->COMGETTER(UseHostIOCache)(&fUseHostIOCache); H();
2146
2147 BOOL fBootable;
2148 rc = ctrls[i]->COMGETTER(Bootable)(&fBootable); H();
2149
2150 PCFGMNODE pCtlInst = NULL;
2151 const char *pszCtrlDev = i_storageControllerTypeToStr(enmCtrlType);
2152 if (enmCtrlType != StorageControllerType_USB)
2153 {
2154 /* /Devices/<ctrldev>/ */
2155 pDev = aCtrlNodes[enmCtrlType];
2156 if (!pDev)
2157 {
2158 InsertConfigNode(pDevices, pszCtrlDev, &pDev);
2159 aCtrlNodes[enmCtrlType] = pDev; /* IDE variants are handled in the switch */
2160 }
2161
2162 /* /Devices/<ctrldev>/<instance>/ */
2163 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pCtlInst);
2164
2165 /* Device config: /Devices/<ctrldev>/<instance>/<values> & /ditto/Config/<values> */
2166 InsertConfigInteger(pCtlInst, "Trusted", 1);
2167 InsertConfigNode(pCtlInst, "Config", &pCfg);
2168 }
2169
2170 static const char * const apszBiosConfigScsi[MAX_BIOS_LUN_COUNT] =
2171 { "ScsiLUN1", "ScsiLUN2", "ScsiLUN3", "ScsiLUN4" };
2172
2173 static const char * const apszBiosConfigSata[MAX_BIOS_LUN_COUNT] =
2174 { "SataLUN1", "SataLUN2", "SataLUN3", "SataLUN4" };
2175
2176 switch (enmCtrlType)
2177 {
2178 case StorageControllerType_LsiLogic:
2179 {
2180 hrc = pBusMgr->assignPCIDevice("lsilogic", pCtlInst); H();
2181
2182 InsertConfigInteger(pCfg, "Bootable", fBootable);
2183
2184 /* BIOS configuration values, first SCSI controller only. */
2185 if ( !pBusMgr->hasPCIDevice("lsilogic", 1)
2186 && !pBusMgr->hasPCIDevice("buslogic", 0)
2187 && !pBusMgr->hasPCIDevice("lsilogicsas", 0)
2188 && pBiosCfg)
2189 {
2190 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "lsilogicscsi");
2191 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();
2192 }
2193
2194 /* Attach the status driver */
2195 Assert(cLedScsi >= 16);
2196 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedScsi], 0, 15,
2197 &mapMediumAttachments, pszCtrlDev, ulInstance);
2198 paLedDevType = &maStorageDevType[iLedScsi];
2199 break;
2200 }
2201
2202 case StorageControllerType_BusLogic:
2203 {
2204 hrc = pBusMgr->assignPCIDevice("buslogic", pCtlInst); H();
2205
2206 InsertConfigInteger(pCfg, "Bootable", fBootable);
2207
2208 /* BIOS configuration values, first SCSI controller only. */
2209 if ( !pBusMgr->hasPCIDevice("lsilogic", 0)
2210 && !pBusMgr->hasPCIDevice("buslogic", 1)
2211 && !pBusMgr->hasPCIDevice("lsilogicsas", 0)
2212 && pBiosCfg)
2213 {
2214 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "buslogic");
2215 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();
2216 }
2217
2218 /* Attach the status driver */
2219 Assert(cLedScsi >= 16);
2220 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedScsi], 0, 15,
2221 &mapMediumAttachments, pszCtrlDev, ulInstance);
2222 paLedDevType = &maStorageDevType[iLedScsi];
2223 break;
2224 }
2225
2226 case StorageControllerType_IntelAhci:
2227 {
2228 hrc = pBusMgr->assignPCIDevice("ahci", pCtlInst); H();
2229
2230 ULONG cPorts = 0;
2231 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
2232 InsertConfigInteger(pCfg, "PortCount", cPorts);
2233 InsertConfigInteger(pCfg, "Bootable", fBootable);
2234
2235 com::SafeIfaceArray<IMediumAttachment> atts;
2236 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),
2237 ComSafeArrayAsOutParam(atts)); H();
2238
2239 /* Configure the hotpluggable flag for the port. */
2240 for (unsigned idxAtt = 0; idxAtt < atts.size(); ++idxAtt)
2241 {
2242 IMediumAttachment *pMediumAtt = atts[idxAtt];
2243
2244 LONG lPortNum = 0;
2245 hrc = pMediumAtt->COMGETTER(Port)(&lPortNum); H();
2246
2247 BOOL fHotPluggable = FALSE;
2248 hrc = pMediumAtt->COMGETTER(HotPluggable)(&fHotPluggable); H();
2249 if (SUCCEEDED(hrc))
2250 {
2251 PCFGMNODE pPortCfg;
2252 char szName[24];
2253 RTStrPrintf(szName, sizeof(szName), "Port%d", lPortNum);
2254
2255 InsertConfigNode(pCfg, szName, &pPortCfg);
2256 InsertConfigInteger(pPortCfg, "Hotpluggable", fHotPluggable ? 1 : 0);
2257 }
2258 }
2259
2260 /* BIOS configuration values, first AHCI controller only. */
2261 if ( !pBusMgr->hasPCIDevice("ahci", 1)
2262 && pBiosCfg)
2263 {
2264 InsertConfigString(pBiosCfg, "SataHardDiskDevice", "ahci");
2265 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigSata); H();
2266 }
2267
2268 /* Attach the status driver */
2269 AssertRelease(cPorts <= cLedSata);
2270 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedSata], 0, cPorts - 1,
2271 &mapMediumAttachments, pszCtrlDev, ulInstance);
2272 paLedDevType = &maStorageDevType[iLedSata];
2273 break;
2274 }
2275
2276 case StorageControllerType_PIIX3:
2277 case StorageControllerType_PIIX4:
2278 case StorageControllerType_ICH6:
2279 {
2280 /*
2281 * IDE (update this when the main interface changes)
2282 */
2283 hrc = pBusMgr->assignPCIDevice("piix3ide", pCtlInst); H();
2284 InsertConfigString(pCfg, "Type", controllerString(enmCtrlType));
2285 /* Attach the status driver */
2286 Assert(cLedIde >= 4);
2287 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedIde], 0, 3,
2288 &mapMediumAttachments, pszCtrlDev, ulInstance);
2289 paLedDevType = &maStorageDevType[iLedIde];
2290
2291 /* IDE flavors */
2292 aCtrlNodes[StorageControllerType_PIIX3] = pDev;
2293 aCtrlNodes[StorageControllerType_PIIX4] = pDev;
2294 aCtrlNodes[StorageControllerType_ICH6] = pDev;
2295 break;
2296 }
2297
2298 case StorageControllerType_I82078:
2299 {
2300 /*
2301 * i82078 Floppy drive controller
2302 */
2303 fFdcEnabled = true;
2304 InsertConfigInteger(pCfg, "IRQ", 6);
2305 InsertConfigInteger(pCfg, "DMA", 2);
2306 InsertConfigInteger(pCfg, "MemMapped", 0 );
2307 InsertConfigInteger(pCfg, "IOBase", 0x3f0);
2308
2309 /* Attach the status driver */
2310 Assert(cLedFloppy >= 2);
2311 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedFloppy], 0, 1,
2312 &mapMediumAttachments, pszCtrlDev, ulInstance);
2313 paLedDevType = &maStorageDevType[iLedFloppy];
2314 break;
2315 }
2316
2317 case StorageControllerType_LsiLogicSas:
2318 {
2319 hrc = pBusMgr->assignPCIDevice("lsilogicsas", pCtlInst); H();
2320
2321 InsertConfigString(pCfg, "ControllerType", "SAS1068");
2322 InsertConfigInteger(pCfg, "Bootable", fBootable);
2323
2324 /* BIOS configuration values, first SCSI controller only. */
2325 if ( !pBusMgr->hasPCIDevice("lsilogic", 0)
2326 && !pBusMgr->hasPCIDevice("buslogic", 0)
2327 && !pBusMgr->hasPCIDevice("lsilogicsas", 1)
2328 && pBiosCfg)
2329 {
2330 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "lsilogicsas");
2331 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();
2332 }
2333
2334 ULONG cPorts = 0;
2335 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
2336 InsertConfigInteger(pCfg, "NumPorts", cPorts);
2337
2338 /* Attach the status driver */
2339 Assert(cLedSas >= 8);
2340 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedSas], 0, 7,
2341 &mapMediumAttachments, pszCtrlDev, ulInstance);
2342 paLedDevType = &maStorageDevType[iLedSas];
2343 break;
2344 }
2345
2346 case StorageControllerType_USB:
2347 {
2348 if (pUsbDevices)
2349 {
2350 /*
2351 * USB MSDs are handled a bit different as the device instance
2352 * doesn't match the storage controller instance but the port.
2353 */
2354 InsertConfigNode(pUsbDevices, "Msd", &pDev);
2355 pCtlInst = pDev;
2356 }
2357 else
2358 return VMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
2359 N_("There is no USB controller enabled but there\n"
2360 "is at least one USB storage device configured for this VM.\n"
2361 "To fix this problem either enable the USB controller or remove\n"
2362 "the storage device from the VM"));
2363 break;
2364 }
2365
2366 case StorageControllerType_NVMe:
2367 {
2368 hrc = pBusMgr->assignPCIDevice("nvme", pCtlInst); H();
2369
2370 ULONG cPorts = 0;
2371 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
2372 InsertConfigInteger(pCfg, "NamespacesMax", cPorts);
2373
2374 /* Attach the status driver */
2375 AssertRelease(cPorts <= cLedSata);
2376 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedNvme], 0, cPorts - 1,
2377 &mapMediumAttachments, pszCtrlDev, ulInstance);
2378 paLedDevType = &maStorageDevType[iLedNvme];
2379 break;
2380 }
2381
2382 case StorageControllerType_VirtioSCSI:
2383 {
2384 hrc = pBusMgr->assignPCIDevice("virtio-scsi", pCtlInst); H();
2385
2386 ULONG cPorts = 0;
2387 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
2388 InsertConfigInteger(pCfg, "NumTargets", cPorts);
2389 InsertConfigInteger(pCfg, "Bootable", fBootable);
2390
2391 /* Attach the status driver */
2392 AssertRelease(cPorts <= cLedSata);
2393 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedVirtio], 0, cPorts - 1,
2394 &mapMediumAttachments, pszCtrlDev, ulInstance);
2395 paLedDevType = &maStorageDevType[iLedVirtio];
2396 break;
2397 }
2398
2399 default:
2400 AssertLogRelMsgFailedReturn(("invalid storage controller type: %d\n", enmCtrlType), VERR_MAIN_CONFIG_CONSTRUCTOR_IPE);
2401 }
2402
2403 /* Attach the media to the storage controllers. */
2404 com::SafeIfaceArray<IMediumAttachment> atts;
2405 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),
2406 ComSafeArrayAsOutParam(atts)); H();
2407
2408 /* Builtin I/O cache - per device setting. */
2409 BOOL fBuiltinIOCache = true;
2410 hrc = pMachine->COMGETTER(IOCacheEnabled)(&fBuiltinIOCache); H();
2411
2412 bool fInsertDiskIntegrityDrv = false;
2413 Bstr strDiskIntegrityFlag;
2414 hrc = pMachine->GetExtraData(Bstr("VBoxInternal2/EnableDiskIntegrityDriver").raw(),
2415 strDiskIntegrityFlag.asOutParam());
2416 if ( hrc == S_OK
2417 && strDiskIntegrityFlag == "1")
2418 fInsertDiskIntegrityDrv = true;
2419
2420 for (size_t j = 0; j < atts.size(); ++j)
2421 {
2422 IMediumAttachment *pMediumAtt = atts[j];
2423 rc = i_configMediumAttachment(pszCtrlDev,
2424 ulInstance,
2425 enmBus,
2426 !!fUseHostIOCache,
2427 enmCtrlType == StorageControllerType_NVMe ? false : !!fBuiltinIOCache,
2428 fInsertDiskIntegrityDrv,
2429 false /* fSetupMerge */,
2430 0 /* uMergeSource */,
2431 0 /* uMergeTarget */,
2432 pMediumAtt,
2433 mMachineState,
2434 NULL /* phrc */,
2435 false /* fAttachDetach */,
2436 false /* fForceUnmount */,
2437 false /* fHotplug */,
2438 pUVM,
2439 paLedDevType,
2440 NULL /* ppLunL0 */);
2441 if (RT_FAILURE(rc))
2442 return rc;
2443 }
2444 H();
2445 }
2446 H();
2447
2448 /*
2449 * Network adapters
2450 */
2451#ifdef VMWARE_NET_IN_SLOT_11
2452 bool fSwapSlots3and11 = false;
2453#endif
2454 PCFGMNODE pDevPCNet = NULL; /* PCNet-type devices */
2455 InsertConfigNode(pDevices, "pcnet", &pDevPCNet);
2456#ifdef VBOX_WITH_E1000
2457 PCFGMNODE pDevE1000 = NULL; /* E1000-type devices */
2458 InsertConfigNode(pDevices, "e1000", &pDevE1000);
2459#endif
2460#ifdef VBOX_WITH_VIRTIO
2461 PCFGMNODE pDevVirtioNet = NULL; /* Virtio network devices */
2462 InsertConfigNode(pDevices, "virtio-net", &pDevVirtioNet);
2463#endif /* VBOX_WITH_VIRTIO */
2464 std::list<BootNic> llBootNics;
2465 for (ULONG ulInstance = 0; ulInstance < maxNetworkAdapters; ++ulInstance)
2466 {
2467 ComPtr<INetworkAdapter> networkAdapter;
2468 hrc = pMachine->GetNetworkAdapter(ulInstance, networkAdapter.asOutParam()); H();
2469 BOOL fEnabledNetAdapter = FALSE;
2470 hrc = networkAdapter->COMGETTER(Enabled)(&fEnabledNetAdapter); H();
2471 if (!fEnabledNetAdapter)
2472 continue;
2473
2474 /*
2475 * The virtual hardware type. Create appropriate device first.
2476 */
2477 const char *pszAdapterName = "pcnet";
2478 NetworkAdapterType_T adapterType;
2479 hrc = networkAdapter->COMGETTER(AdapterType)(&adapterType); H();
2480 switch (adapterType)
2481 {
2482 case NetworkAdapterType_Am79C970A:
2483 case NetworkAdapterType_Am79C973:
2484 case NetworkAdapterType_Am79C960:
2485 pDev = pDevPCNet;
2486 break;
2487#ifdef VBOX_WITH_E1000
2488 case NetworkAdapterType_I82540EM:
2489 case NetworkAdapterType_I82543GC:
2490 case NetworkAdapterType_I82545EM:
2491 pDev = pDevE1000;
2492 pszAdapterName = "e1000";
2493 break;
2494#endif
2495#ifdef VBOX_WITH_VIRTIO
2496 case NetworkAdapterType_Virtio:
2497 pDev = pDevVirtioNet;
2498 pszAdapterName = "virtio-net";
2499 break;
2500#endif /* VBOX_WITH_VIRTIO */
2501 default:
2502 AssertMsgFailed(("Invalid network adapter type '%d' for slot '%d'",
2503 adapterType, ulInstance));
2504 return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
2505 N_("Invalid network adapter type '%d' for slot '%d'"),
2506 adapterType, ulInstance);
2507 }
2508
2509 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
2510 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2511 /* the first network card gets the PCI ID 3, the next 3 gets 8..10,
2512 * next 4 get 16..19. */
2513 int iPCIDeviceNo;
2514 switch (ulInstance)
2515 {
2516 case 0:
2517 iPCIDeviceNo = 3;
2518 break;
2519 case 1: case 2: case 3:
2520 iPCIDeviceNo = ulInstance - 1 + 8;
2521 break;
2522 case 4: case 5: case 6: case 7:
2523 iPCIDeviceNo = ulInstance - 4 + 16;
2524 break;
2525 default:
2526 /* auto assignment */
2527 iPCIDeviceNo = -1;
2528 break;
2529 }
2530#ifdef VMWARE_NET_IN_SLOT_11
2531 /*
2532 * Dirty hack for PCI slot compatibility with VMWare,
2533 * it assigns slot 0x11 to the first network controller.
2534 */
2535 if (iPCIDeviceNo == 3 && adapterType == NetworkAdapterType_I82545EM)
2536 {
2537 iPCIDeviceNo = 0x11;
2538 fSwapSlots3and11 = true;
2539 }
2540 else if (iPCIDeviceNo == 0x11 && fSwapSlots3and11)
2541 iPCIDeviceNo = 3;
2542#endif
2543 PCIBusAddress PCIAddr = PCIBusAddress(0, iPCIDeviceNo, 0);
2544 hrc = pBusMgr->assignPCIDevice(pszAdapterName, pInst, PCIAddr); H();
2545
2546 InsertConfigNode(pInst, "Config", &pCfg);
2547#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE /* not safe here yet. */ /** @todo Make PCNet ring-0 safe on 32-bit mac kernels! */
2548 if (pDev == pDevPCNet)
2549 {
2550 InsertConfigInteger(pCfg, "R0Enabled", false);
2551 }
2552#endif
2553 /*
2554 * Collect information needed for network booting and add it to the list.
2555 */
2556 BootNic nic;
2557
2558 nic.mInstance = ulInstance;
2559 /* Could be updated by reference, if auto assigned */
2560 nic.mPCIAddress = PCIAddr;
2561
2562 hrc = networkAdapter->COMGETTER(BootPriority)(&nic.mBootPrio); H();
2563
2564 llBootNics.push_back(nic);
2565
2566 /*
2567 * The virtual hardware type. PCNet supports two types, E1000 three,
2568 * but VirtIO only one.
2569 */
2570 switch (adapterType)
2571 {
2572 case NetworkAdapterType_Am79C970A:
2573 InsertConfigString(pCfg, "ChipType", "Am79C970A");
2574 break;
2575 case NetworkAdapterType_Am79C973:
2576 InsertConfigString(pCfg, "ChipType", "Am79C973");
2577 break;
2578 case NetworkAdapterType_Am79C960:
2579 InsertConfigString(pCfg, "ChipType", "Am79C960");
2580 break;
2581 case NetworkAdapterType_I82540EM:
2582 InsertConfigInteger(pCfg, "AdapterType", 0);
2583 break;
2584 case NetworkAdapterType_I82543GC:
2585 InsertConfigInteger(pCfg, "AdapterType", 1);
2586 break;
2587 case NetworkAdapterType_I82545EM:
2588 InsertConfigInteger(pCfg, "AdapterType", 2);
2589 break;
2590 case NetworkAdapterType_Virtio:
2591 break;
2592 case NetworkAdapterType_Null: AssertFailedBreak(); /* (compiler warnings) */
2593#ifdef VBOX_WITH_XPCOM_CPP_ENUM_HACK
2594 case NetworkAdapterType_32BitHack: AssertFailedBreak(); /* (compiler warnings) */
2595#endif
2596 }
2597
2598 /*
2599 * Get the MAC address and convert it to binary representation
2600 */
2601 Bstr macAddr;
2602 hrc = networkAdapter->COMGETTER(MACAddress)(macAddr.asOutParam()); H();
2603 Assert(!macAddr.isEmpty());
2604 Utf8Str macAddrUtf8 = macAddr;
2605 char *macStr = (char*)macAddrUtf8.c_str();
2606 Assert(strlen(macStr) == 12);
2607 RTMAC Mac;
2608 RT_ZERO(Mac);
2609 char *pMac = (char*)&Mac;
2610 for (uint32_t i = 0; i < 6; ++i)
2611 {
2612 int c1 = *macStr++ - '0';
2613 if (c1 > 9)
2614 c1 -= 7;
2615 int c2 = *macStr++ - '0';
2616 if (c2 > 9)
2617 c2 -= 7;
2618 *pMac++ = (char)(((c1 & 0x0f) << 4) | (c2 & 0x0f));
2619 }
2620 InsertConfigBytes(pCfg, "MAC", &Mac, sizeof(Mac));
2621
2622 /*
2623 * Check if the cable is supposed to be unplugged
2624 */
2625 BOOL fCableConnected;
2626 hrc = networkAdapter->COMGETTER(CableConnected)(&fCableConnected); H();
2627 InsertConfigInteger(pCfg, "CableConnected", fCableConnected ? 1 : 0);
2628
2629 /*
2630 * Line speed to report from custom drivers
2631 */
2632 ULONG ulLineSpeed;
2633 hrc = networkAdapter->COMGETTER(LineSpeed)(&ulLineSpeed); H();
2634 InsertConfigInteger(pCfg, "LineSpeed", ulLineSpeed);
2635
2636 /*
2637 * Attach the status driver.
2638 */
2639 i_attachStatusDriver(pInst, &mapNetworkLeds[ulInstance], 0, 0, NULL, NULL, 0);
2640
2641 /*
2642 * Configure the network card now
2643 */
2644 bool fIgnoreConnectFailure = mMachineState == MachineState_Restoring;
2645 rc = i_configNetwork(pszAdapterName,
2646 ulInstance,
2647 0,
2648 networkAdapter,
2649 pCfg,
2650 pLunL0,
2651 pInst,
2652 false /*fAttachDetach*/,
2653 fIgnoreConnectFailure);
2654 if (RT_FAILURE(rc))
2655 return rc;
2656 }
2657
2658 /*
2659 * Build network boot information and transfer it to the BIOS.
2660 */
2661 if (pNetBootCfg && !llBootNics.empty()) /* NetBoot node doesn't exist for EFI! */
2662 {
2663 llBootNics.sort(); /* Sort the list by boot priority. */
2664
2665 char achBootIdx[] = "0";
2666 unsigned uBootIdx = 0;
2667
2668 for (std::list<BootNic>::iterator it = llBootNics.begin(); it != llBootNics.end(); ++it)
2669 {
2670 /* A NIC with priority 0 is only used if it's first in the list. */
2671 if (it->mBootPrio == 0 && uBootIdx != 0)
2672 break;
2673
2674 PCFGMNODE pNetBtDevCfg;
2675 achBootIdx[0] = (char)('0' + uBootIdx++); /* Boot device order. */
2676 InsertConfigNode(pNetBootCfg, achBootIdx, &pNetBtDevCfg);
2677 InsertConfigInteger(pNetBtDevCfg, "NIC", it->mInstance);
2678 InsertConfigInteger(pNetBtDevCfg, "PCIBusNo", it->mPCIAddress.miBus);
2679 InsertConfigInteger(pNetBtDevCfg, "PCIDeviceNo", it->mPCIAddress.miDevice);
2680 InsertConfigInteger(pNetBtDevCfg, "PCIFunctionNo", it->mPCIAddress.miFn);
2681 }
2682 }
2683
2684 /*
2685 * Serial (UART) Ports
2686 */
2687 /* serial enabled mask to be passed to dev ACPI */
2688 uint16_t auSerialIoPortBase[SchemaDefs::SerialPortCount] = {0};
2689 uint8_t auSerialIrq[SchemaDefs::SerialPortCount] = {0};
2690 InsertConfigNode(pDevices, "serial", &pDev);
2691 for (ULONG ulInstance = 0; ulInstance < SchemaDefs::SerialPortCount; ++ulInstance)
2692 {
2693 ComPtr<ISerialPort> serialPort;
2694 hrc = pMachine->GetSerialPort(ulInstance, serialPort.asOutParam()); H();
2695 BOOL fEnabledSerPort = FALSE;
2696 if (serialPort)
2697 {
2698 hrc = serialPort->COMGETTER(Enabled)(&fEnabledSerPort); H();
2699 }
2700 if (!fEnabledSerPort)
2701 {
2702 m_aeSerialPortMode[ulInstance] = PortMode_Disconnected;
2703 continue;
2704 }
2705
2706 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
2707 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2708 InsertConfigNode(pInst, "Config", &pCfg);
2709
2710 ULONG ulIRQ;
2711 hrc = serialPort->COMGETTER(IRQ)(&ulIRQ); H();
2712 InsertConfigInteger(pCfg, "IRQ", ulIRQ);
2713 auSerialIrq[ulInstance] = (uint8_t)ulIRQ;
2714
2715 ULONG ulIOBase;
2716 hrc = serialPort->COMGETTER(IOBase)(&ulIOBase); H();
2717 InsertConfigInteger(pCfg, "IOBase", ulIOBase);
2718 auSerialIoPortBase[ulInstance] = (uint16_t)ulIOBase;
2719
2720 BOOL fServer;
2721 hrc = serialPort->COMGETTER(Server)(&fServer); H();
2722 hrc = serialPort->COMGETTER(Path)(bstr.asOutParam()); H();
2723 UartType_T eUartType;
2724 const char *pszUartType;
2725 hrc = serialPort->COMGETTER(UartType)(&eUartType); H();
2726 switch (eUartType)
2727 {
2728 case UartType_U16450: pszUartType = "16450"; break;
2729 case UartType_U16750: pszUartType = "16750"; break;
2730 default: AssertFailed(); RT_FALL_THRU();
2731 case UartType_U16550A: pszUartType = "16550A"; break;
2732 }
2733 InsertConfigString(pCfg, "UartType", pszUartType);
2734
2735 PortMode_T eHostMode;
2736 hrc = serialPort->COMGETTER(HostMode)(&eHostMode); H();
2737
2738 m_aeSerialPortMode[ulInstance] = eHostMode;
2739 if (eHostMode != PortMode_Disconnected)
2740 {
2741 rc = i_configSerialPort(pInst, eHostMode, Utf8Str(bstr).c_str(), RT_BOOL(fServer));
2742 if (RT_FAILURE(rc))
2743 return rc;
2744 }
2745 }
2746
2747 /*
2748 * Parallel (LPT) Ports
2749 */
2750 /* parallel enabled mask to be passed to dev ACPI */
2751 uint16_t auParallelIoPortBase[SchemaDefs::ParallelPortCount] = {0};
2752 uint8_t auParallelIrq[SchemaDefs::ParallelPortCount] = {0};
2753 InsertConfigNode(pDevices, "parallel", &pDev);
2754 for (ULONG ulInstance = 0; ulInstance < SchemaDefs::ParallelPortCount; ++ulInstance)
2755 {
2756 ComPtr<IParallelPort> parallelPort;
2757 hrc = pMachine->GetParallelPort(ulInstance, parallelPort.asOutParam()); H();
2758 BOOL fEnabledParPort = FALSE;
2759 if (parallelPort)
2760 {
2761 hrc = parallelPort->COMGETTER(Enabled)(&fEnabledParPort); H();
2762 }
2763 if (!fEnabledParPort)
2764 continue;
2765
2766 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
2767 InsertConfigNode(pInst, "Config", &pCfg);
2768
2769 ULONG ulIRQ;
2770 hrc = parallelPort->COMGETTER(IRQ)(&ulIRQ); H();
2771 InsertConfigInteger(pCfg, "IRQ", ulIRQ);
2772 auParallelIrq[ulInstance] = (uint8_t)ulIRQ;
2773 ULONG ulIOBase;
2774 hrc = parallelPort->COMGETTER(IOBase)(&ulIOBase); H();
2775 InsertConfigInteger(pCfg, "IOBase", ulIOBase);
2776 auParallelIoPortBase[ulInstance] = (uint16_t)ulIOBase;
2777
2778 hrc = parallelPort->COMGETTER(Path)(bstr.asOutParam()); H();
2779 if (!bstr.isEmpty())
2780 {
2781 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2782 InsertConfigString(pLunL0, "Driver", "HostParallel");
2783 InsertConfigNode(pLunL0, "Config", &pLunL1);
2784 InsertConfigString(pLunL1, "DevicePath", bstr);
2785 }
2786 }
2787
2788 /*
2789 * VMM Device
2790 */
2791 InsertConfigNode(pDevices, "VMMDev", &pDev);
2792 InsertConfigNode(pDev, "0", &pInst);
2793 InsertConfigNode(pInst, "Config", &pCfg);
2794 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2795 hrc = pBusMgr->assignPCIDevice("VMMDev", pInst); H();
2796
2797 Bstr hwVersion;
2798 hrc = pMachine->COMGETTER(HardwareVersion)(hwVersion.asOutParam()); H();
2799 if (hwVersion.compare(Bstr("1").raw()) == 0) /* <= 2.0.x */
2800 InsertConfigInteger(pCfg, "HeapEnabled", 0);
2801 Bstr snapshotFolder;
2802 hrc = pMachine->COMGETTER(SnapshotFolder)(snapshotFolder.asOutParam()); H();
2803 InsertConfigString(pCfg, "GuestCoreDumpDir", snapshotFolder);
2804
2805 /* the VMM device's Main driver */
2806 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2807 InsertConfigString(pLunL0, "Driver", "HGCM");
2808 InsertConfigNode(pLunL0, "Config", &pCfg);
2809 InsertConfigInteger(pCfg, "Object", (uintptr_t)pVMMDev);
2810
2811 /*
2812 * Attach the status driver.
2813 */
2814 i_attachStatusDriver(pInst, &mapSharedFolderLed, 0, 0, NULL, NULL, 0);
2815
2816 /*
2817 * AC'97 ICH / SoundBlaster16 audio / Intel HD Audio.
2818 */
2819 BOOL fAudioEnabled = FALSE;
2820 ComPtr<IAudioAdapter> audioAdapter;
2821 hrc = pMachine->COMGETTER(AudioAdapter)(audioAdapter.asOutParam()); H();
2822 if (audioAdapter)
2823 {
2824 hrc = audioAdapter->COMGETTER(Enabled)(&fAudioEnabled); H();
2825 }
2826
2827 if (fAudioEnabled)
2828 {
2829 Utf8Str strAudioDevice;
2830
2831 AudioControllerType_T audioController;
2832 hrc = audioAdapter->COMGETTER(AudioController)(&audioController); H();
2833 AudioCodecType_T audioCodec;
2834 hrc = audioAdapter->COMGETTER(AudioCodec)(&audioCodec); H();
2835
2836 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/Debug/Enabled", &strTmp);
2837 const uint64_t fDebugEnabled = (strTmp.equalsIgnoreCase("true") || strTmp.equalsIgnoreCase("1")) ? 1 : 0;
2838
2839 Utf8Str strDebugPathOut;
2840 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/Debug/PathOut", &strDebugPathOut);
2841
2842 /** @todo Implement an audio device class, similar to the audio backend class, to construct the common stuff
2843 * without duplicating (more) code. */
2844
2845 switch (audioController)
2846 {
2847 case AudioControllerType_AC97:
2848 {
2849 /* ICH AC'97. */
2850 strAudioDevice = "ichac97";
2851
2852 InsertConfigNode (pDevices, strAudioDevice.c_str(), &pDev);
2853 InsertConfigNode (pDev, "0", &pInst);
2854 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2855 hrc = pBusMgr->assignPCIDevice(strAudioDevice.c_str(), pInst); H();
2856 InsertConfigNode (pInst, "Config", &pCfg);
2857 switch (audioCodec)
2858 {
2859 case AudioCodecType_STAC9700:
2860 InsertConfigString(pCfg, "Codec", "STAC9700");
2861 break;
2862 case AudioCodecType_AD1980:
2863 InsertConfigString(pCfg, "Codec", "AD1980");
2864 break;
2865 default: AssertFailedBreak();
2866 }
2867 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
2868 InsertConfigString (pCfg, "DebugPathOut", strDebugPathOut);
2869 break;
2870 }
2871 case AudioControllerType_SB16:
2872 {
2873 /* Legacy SoundBlaster16. */
2874 strAudioDevice = "sb16";
2875
2876 InsertConfigNode (pDevices, strAudioDevice.c_str(), &pDev);
2877 InsertConfigNode (pDev, "0", &pInst);
2878 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2879 InsertConfigNode (pInst, "Config", &pCfg);
2880 InsertConfigInteger(pCfg, "IRQ", 5);
2881 InsertConfigInteger(pCfg, "DMA", 1);
2882 InsertConfigInteger(pCfg, "DMA16", 5);
2883 InsertConfigInteger(pCfg, "Port", 0x220);
2884 InsertConfigInteger(pCfg, "Version", 0x0405);
2885 break;
2886 }
2887 case AudioControllerType_HDA:
2888 {
2889 /* Intel HD Audio. */
2890 strAudioDevice = "hda";
2891
2892 InsertConfigNode (pDevices, strAudioDevice.c_str(), &pDev);
2893 InsertConfigNode (pDev, "0", &pInst);
2894 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2895 hrc = pBusMgr->assignPCIDevice(strAudioDevice.c_str(), pInst); H();
2896 InsertConfigNode (pInst, "Config", &pCfg);
2897 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
2898 InsertConfigString (pCfg, "DebugPathOut", strDebugPathOut);
2899 break;
2900 }
2901 default: AssertFailedBreak();
2902 }
2903
2904 PCFGMNODE pCfgAudioAdapter = NULL;
2905 InsertConfigNode(pInst, "AudioConfig", &pCfgAudioAdapter);
2906 SafeArray<BSTR> audioProps;
2907 hrc = audioAdapter->COMGETTER(PropertiesList)(ComSafeArrayAsOutParam(audioProps)); H();
2908
2909 std::list<Utf8Str> audioPropertyNamesList;
2910 for (size_t i = 0; i < audioProps.size(); ++i)
2911 {
2912 Bstr bstrValue;
2913 audioPropertyNamesList.push_back(Utf8Str(audioProps[i]));
2914 hrc = audioAdapter->GetProperty(audioProps[i], bstrValue.asOutParam());
2915 Utf8Str strKey(audioProps[i]);
2916 InsertConfigString(pCfgAudioAdapter, strKey.c_str(), bstrValue);
2917 }
2918
2919 /*
2920 * The audio driver.
2921 */
2922 Utf8Str strAudioDriver;
2923
2924 AudioDriverType_T audioDriver;
2925 hrc = audioAdapter->COMGETTER(AudioDriver)(&audioDriver); H();
2926 switch (audioDriver)
2927 {
2928 case AudioDriverType_Null:
2929 {
2930 strAudioDriver = "NullAudio";
2931 break;
2932 }
2933#ifdef RT_OS_WINDOWS
2934# ifdef VBOX_WITH_WINMM
2935 case AudioDriverType_WinMM:
2936 {
2937 #error "Port WinMM audio backend!" /** @todo Still needed? */
2938 break;
2939 }
2940# endif
2941 case AudioDriverType_DirectSound:
2942 {
2943 strAudioDriver = "DSoundAudio";
2944 break;
2945 }
2946#endif /* RT_OS_WINDOWS */
2947#ifdef RT_OS_SOLARIS
2948 case AudioDriverType_SolAudio:
2949 {
2950 /* Should not happen, as the Solaris Audio backend is not around anymore.
2951 * Remove this sometime later. */
2952 LogRel(("Audio: WARNING: Solaris Audio is deprecated, please switch to OSS!\n"));
2953 LogRel(("Audio: Automatically setting host audio backend to OSS\n"));
2954
2955 /* Manually set backend to OSS for now. */
2956 strAudioDriver = "OSSAudio";
2957 break;
2958 }
2959#endif
2960#ifdef VBOX_WITH_AUDIO_OSS
2961 case AudioDriverType_OSS:
2962 {
2963 strAudioDriver = "OSSAudio";
2964 break;
2965 }
2966#endif
2967#ifdef VBOX_WITH_AUDIO_ALSA
2968 case AudioDriverType_ALSA:
2969 {
2970 strAudioDriver = "ALSAAudio";
2971 break;
2972 }
2973#endif
2974#ifdef VBOX_WITH_AUDIO_PULSE
2975 case AudioDriverType_Pulse:
2976 {
2977 strAudioDriver = "PulseAudio";
2978 break;
2979 }
2980#endif
2981#ifdef RT_OS_DARWIN
2982 case AudioDriverType_CoreAudio:
2983 {
2984 strAudioDriver = "CoreAudio";
2985 break;
2986 }
2987#endif
2988 default: AssertFailedBreak();
2989 }
2990
2991 unsigned uAudioLUN = 0;
2992
2993 CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%RU8", uAudioLUN);
2994 rc = i_configAudioDriver(audioAdapter, virtualBox, pMachine, pLunL0,
2995 strAudioDriver.c_str());
2996 if (RT_SUCCESS(rc))
2997 uAudioLUN++;
2998
2999#ifdef VBOX_WITH_AUDIO_VRDE
3000 /* Insert dummy audio driver to have the LUN configured. */
3001 CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%RU8", uAudioLUN);
3002 InsertConfigString(pLunL0, "Driver", "AUDIO");
3003 AudioDriverCfg DrvCfgVRDE(strAudioDevice, 0 /* Instance */, uAudioLUN, "AudioVRDE");
3004 rc = mAudioVRDE->InitializeConfig(&DrvCfgVRDE);
3005 if (RT_SUCCESS(rc))
3006 uAudioLUN++;
3007#endif /* VBOX_WITH_AUDIO_VRDE */
3008
3009#ifdef VBOX_WITH_AUDIO_RECORDING
3010 /* Insert dummy audio driver to have the LUN configured. */
3011 CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%RU8", uAudioLUN);
3012 InsertConfigString(pLunL0, "Driver", "AUDIO");
3013 AudioDriverCfg DrvCfgVideoRec(strAudioDevice, 0 /* Instance */, uAudioLUN, "AudioVideoRec");
3014 rc = Recording.mAudioRec->InitializeConfig(&DrvCfgVideoRec);
3015 if (RT_SUCCESS(rc))
3016 uAudioLUN++;
3017#endif /* VBOX_WITH_AUDIO_RECORDING */
3018
3019 if (fDebugEnabled)
3020 {
3021#ifdef VBOX_WITH_AUDIO_DEBUG
3022 CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%RU8", uAudioLUN);
3023 rc = i_configAudioDriver(audioAdapter, virtualBox, pMachine, pLunL0,
3024 "DebugAudio");
3025 if (RT_SUCCESS(rc))
3026 uAudioLUN++;
3027#endif /* VBOX_WITH_AUDIO_DEBUG */
3028
3029 /*
3030 * Tweak the logging groups.
3031 */
3032 Utf8Str strLogGroups = "drv_host_audio.e.l.l2.l3.f+" \
3033 "drv_audio.e.l.l2.l3.f+" \
3034 "audio_mixer.e.l.l2.l3.f+" \
3035 "dev_hda_codec.e.l.l2.l3.f+" \
3036 "dev_hda.e.l.l2.l3.f+" \
3037 "dev_ac97.e.l.l2.l3.f+" \
3038 "dev_sb16.e.l.l2.l3.f";
3039
3040 rc = RTLogGroupSettings(RTLogRelGetDefaultInstance(), strLogGroups.c_str());
3041 if (RT_FAILURE(rc))
3042 LogRel(("Audio: Setting debug logging failed, rc=%Rrc\n", rc));
3043 }
3044
3045#ifdef VBOX_WITH_AUDIO_VALIDATIONKIT
3046 /** @todo Make this a runtime-configurable entry! */
3047
3048 /*
3049 * The ValidationKit backend.
3050 */
3051 CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%RU8", uAudioLUN);
3052 rc = i_configAudioDriver(audioAdapter, virtualBox, pMachine, pLunL0,
3053 "ValidationKitAudio");
3054 if (RT_SUCCESS(rc))
3055 uAudioLUN++;
3056#endif /* VBOX_WITH_AUDIO_VALIDATIONKIT */
3057 }
3058
3059#ifdef VBOX_WITH_SHARED_CLIPBOARD
3060 /*
3061 * Shared Clipboard.
3062 */
3063 {
3064 if (SharedClipboard::createInstance(this /* pConsole */) == NULL)
3065 {
3066 rc = VERR_NO_MEMORY;
3067 }
3068 else
3069 {
3070 /* Load the service */
3071 rc = pVMMDev->hgcmLoadService("VBoxSharedClipboard", "VBoxSharedClipboard");
3072 if (RT_SUCCESS(rc))
3073 {
3074 LogRel(("Shared Clipboard: Service loaded\n"));
3075 rc = HGCMHostRegisterServiceExtension(&m_hHgcmSvcExtShrdClipboard, "VBoxSharedClipboard",
3076 &Console::i_sharedClipboardServiceCallback,
3077 this /* pvExtension */);
3078 if (RT_FAILURE(rc))
3079 {
3080 LogRel(("Shared Clipboard: Cannot register service extension, rc=%Rrc\n", rc));
3081 }
3082 else
3083 {
3084 /* Set initial clipboard mode. */
3085 ClipboardMode_T mode = ClipboardMode_Disabled;
3086 hrc = pMachine->COMGETTER(ClipboardMode)(&mode); H();
3087
3088 rc = i_changeClipboardMode(mode);
3089 if (RT_SUCCESS(rc))
3090 {
3091 /* Setup the service. */
3092 VBOXHGCMSVCPARM parm;
3093 HGCMSvcSetU32(&parm, !i_useHostClipboard());
3094 rc = SHAREDCLIPBOARDINST()->hostCall(VBOX_SHCL_HOST_FN_SET_HEADLESS, 1, &parm);
3095 if (RT_FAILURE(rc))
3096 LogRel(("Shared Clipboard: Unable to set initial headless mode, rc=%Rrc\n", rc));
3097
3098#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
3099 /* Setup file transfer mode. */
3100 BOOL fFileTransfersEnabled;
3101 hrc = pMachine->COMGETTER(ClipboardFileTransfersEnabled)(&fFileTransfersEnabled); H();
3102 int rc2 = i_changeClipboardFileTransferMode(RT_BOOL(fFileTransfersEnabled));
3103 if (RT_FAILURE(rc2))
3104 LogRel(("Shared Clipboard: Unable to set initial file transfers mode, rc=%Rrc\n", rc2));
3105 /* Note: Don't let the Shared Clipboard fail as a whole if file transfers aren't available. */
3106#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
3107 }
3108 else
3109 LogRel(("Shared Clipboard: Unable to set initial clipboard mode, rc=%Rrc\n", rc));
3110 }
3111 }
3112 }
3113
3114 if (RT_FAILURE(rc))
3115 {
3116 LogRel(("Shared Clipboard: Not available, rc=%Rrc\n", rc));
3117 /* That is not a fatal failure. */
3118 rc = VINF_SUCCESS;
3119 }
3120 }
3121#endif /* VBOX_WITH_SHARED_CLIPBOARD */
3122
3123 /*
3124 * HGCM HostChannel.
3125 */
3126 {
3127 Bstr value;
3128 hrc = pMachine->GetExtraData(Bstr("HGCM/HostChannel").raw(),
3129 value.asOutParam());
3130
3131 if ( hrc == S_OK
3132 && value == "1")
3133 {
3134 rc = pVMMDev->hgcmLoadService("VBoxHostChannel", "VBoxHostChannel");
3135 if (RT_FAILURE(rc))
3136 {
3137 LogRel(("VBoxHostChannel is not available, rc=%Rrc\n", rc));
3138 /* That is not a fatal failure. */
3139 rc = VINF_SUCCESS;
3140 }
3141 }
3142 }
3143
3144#ifdef VBOX_WITH_DRAG_AND_DROP
3145 /*
3146 * Drag and Drop.
3147 */
3148 {
3149 DnDMode_T enmMode = DnDMode_Disabled;
3150 hrc = pMachine->COMGETTER(DnDMode)(&enmMode); H();
3151
3152 /* Load the service */
3153 rc = pVMMDev->hgcmLoadService("VBoxDragAndDropSvc", "VBoxDragAndDropSvc");
3154 if (RT_FAILURE(rc))
3155 {
3156 LogRel(("Drag and drop service is not available, rc=%Rrc\n", rc));
3157 /* That is not a fatal failure. */
3158 rc = VINF_SUCCESS;
3159 }
3160 else
3161 {
3162 rc = HGCMHostRegisterServiceExtension(&m_hHgcmSvcExtDragAndDrop, "VBoxDragAndDropSvc",
3163 &GuestDnD::notifyDnDDispatcher,
3164 GUESTDNDINST());
3165 if (RT_FAILURE(rc))
3166 Log(("Cannot register VBoxDragAndDropSvc extension, rc=%Rrc\n", rc));
3167 else
3168 {
3169 LogRel(("Drag and drop service loaded\n"));
3170 rc = i_changeDnDMode(enmMode);
3171 }
3172 }
3173 }
3174#endif /* VBOX_WITH_DRAG_AND_DROP */
3175
3176 /*
3177 * ACPI
3178 */
3179 BOOL fACPI;
3180 hrc = biosSettings->COMGETTER(ACPIEnabled)(&fACPI); H();
3181 if (fACPI)
3182 {
3183 /* Always show the CPU leafs when we have multiple VCPUs or when the IO-APIC is enabled.
3184 * The Windows SMP kernel needs a CPU leaf or else its idle loop will burn cpu cycles; the
3185 * intelppm driver refuses to register an idle state handler.
3186 * Always show CPU leafs for OS X guests. */
3187 BOOL fShowCpu = fOsXGuest;
3188 if (cCpus > 1 || fIOAPIC)
3189 fShowCpu = true;
3190
3191 BOOL fCpuHotPlug;
3192 hrc = pMachine->COMGETTER(CPUHotPlugEnabled)(&fCpuHotPlug); H();
3193
3194 InsertConfigNode(pDevices, "acpi", &pDev);
3195 InsertConfigNode(pDev, "0", &pInst);
3196 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3197 InsertConfigNode(pInst, "Config", &pCfg);
3198 hrc = pBusMgr->assignPCIDevice("acpi", pInst); H();
3199
3200 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
3201
3202 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
3203 InsertConfigInteger(pCfg, "FdcEnabled", fFdcEnabled);
3204 InsertConfigInteger(pCfg, "HpetEnabled", fHPETEnabled);
3205 InsertConfigInteger(pCfg, "SmcEnabled", fSmcEnabled);
3206 InsertConfigInteger(pCfg, "ShowRtc", fShowRtc);
3207 if (fOsXGuest && !llBootNics.empty())
3208 {
3209 BootNic aNic = llBootNics.front();
3210 uint32_t u32NicPCIAddr = (aNic.mPCIAddress.miDevice << 16) | aNic.mPCIAddress.miFn;
3211 InsertConfigInteger(pCfg, "NicPciAddress", u32NicPCIAddr);
3212 }
3213 if (fOsXGuest && fAudioEnabled)
3214 {
3215 PCIBusAddress Address;
3216 if (pBusMgr->findPCIAddress("hda", 0, Address))
3217 {
3218 uint32_t u32AudioPCIAddr = (Address.miDevice << 16) | Address.miFn;
3219 InsertConfigInteger(pCfg, "AudioPciAddress", u32AudioPCIAddr);
3220 }
3221 }
3222 InsertConfigInteger(pCfg, "IocPciAddress", uIocPCIAddress);
3223 if (chipsetType == ChipsetType_ICH9)
3224 {
3225 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
3226 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
3227 /* 64-bit prefetch window root resource:
3228 * Only for ICH9 and if PAE or Long Mode is enabled.
3229 * And only with hardware virtualization (@bugref{5454}). */
3230 if ( (fEnablePAE || fIsGuest64Bit)
3231 && fSupportsHwVirtEx /* HwVirt needs to be supported by the host
3232 otherwise VMM falls back to raw mode */
3233 && fHMEnabled /* HwVirt needs to be enabled in VM config */)
3234 InsertConfigInteger(pCfg, "PciPref64Enabled", 1);
3235 }
3236 InsertConfigInteger(pCfg, "HostBusPciAddress", uHbcPCIAddress);
3237 InsertConfigInteger(pCfg, "ShowCpu", fShowCpu);
3238 InsertConfigInteger(pCfg, "CpuHotPlug", fCpuHotPlug);
3239
3240 InsertConfigInteger(pCfg, "Serial0IoPortBase", auSerialIoPortBase[0]);
3241 InsertConfigInteger(pCfg, "Serial0Irq", auSerialIrq[0]);
3242
3243 InsertConfigInteger(pCfg, "Serial1IoPortBase", auSerialIoPortBase[1]);
3244 InsertConfigInteger(pCfg, "Serial1Irq", auSerialIrq[1]);
3245
3246 if (auSerialIoPortBase[2])
3247 {
3248 InsertConfigInteger(pCfg, "Serial2IoPortBase", auSerialIoPortBase[2]);
3249 InsertConfigInteger(pCfg, "Serial2Irq", auSerialIrq[2]);
3250 }
3251
3252 if (auSerialIoPortBase[3])
3253 {
3254 InsertConfigInteger(pCfg, "Serial3IoPortBase", auSerialIoPortBase[3]);
3255 InsertConfigInteger(pCfg, "Serial3Irq", auSerialIrq[3]);
3256 }
3257
3258 InsertConfigInteger(pCfg, "Parallel0IoPortBase", auParallelIoPortBase[0]);
3259 InsertConfigInteger(pCfg, "Parallel0Irq", auParallelIrq[0]);
3260
3261 InsertConfigInteger(pCfg, "Parallel1IoPortBase", auParallelIoPortBase[1]);
3262 InsertConfigInteger(pCfg, "Parallel1Irq", auParallelIrq[1]);
3263
3264 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3265 InsertConfigString(pLunL0, "Driver", "ACPIHost");
3266 InsertConfigNode(pLunL0, "Config", &pCfg);
3267
3268 /* Attach the dummy CPU drivers */
3269 for (ULONG iCpuCurr = 1; iCpuCurr < cCpus; iCpuCurr++)
3270 {
3271 BOOL fCpuAttached = true;
3272
3273 if (fCpuHotPlug)
3274 {
3275 hrc = pMachine->GetCPUStatus(iCpuCurr, &fCpuAttached); H();
3276 }
3277
3278 if (fCpuAttached)
3279 {
3280 InsertConfigNode(pInst, Utf8StrFmt("LUN#%u", iCpuCurr).c_str(), &pLunL0);
3281 InsertConfigString(pLunL0, "Driver", "ACPICpu");
3282 InsertConfigNode(pLunL0, "Config", &pCfg);
3283 }
3284 }
3285 }
3286
3287 /*
3288 * Configure DBGF (Debug(ger) Facility) and DBGC (Debugger Console).
3289 */
3290 {
3291 PCFGMNODE pDbgf;
3292 InsertConfigNode(pRoot, "DBGF", &pDbgf);
3293
3294 /* Paths to search for debug info and such things. */
3295 hrc = pMachine->COMGETTER(SettingsFilePath)(bstr.asOutParam()); H();
3296 Utf8Str strSettingsPath(bstr);
3297 bstr.setNull();
3298 strSettingsPath.stripFilename();
3299 strSettingsPath.append("/");
3300
3301 char szHomeDir[RTPATH_MAX + 1];
3302 int rc2 = RTPathUserHome(szHomeDir, sizeof(szHomeDir) - 1);
3303 if (RT_FAILURE(rc2))
3304 szHomeDir[0] = '\0';
3305 RTPathEnsureTrailingSeparator(szHomeDir, sizeof(szHomeDir));
3306
3307
3308 Utf8Str strPath;
3309 strPath.append(strSettingsPath).append("debug/;");
3310 strPath.append(strSettingsPath).append(";");
3311 strPath.append(szHomeDir);
3312
3313 InsertConfigString(pDbgf, "Path", strPath.c_str());
3314
3315 /* Tracing configuration. */
3316 BOOL fTracingEnabled;
3317 hrc = pMachine->COMGETTER(TracingEnabled)(&fTracingEnabled); H();
3318 if (fTracingEnabled)
3319 InsertConfigInteger(pDbgf, "TracingEnabled", 1);
3320
3321 hrc = pMachine->COMGETTER(TracingConfig)(bstr.asOutParam()); H();
3322 if (fTracingEnabled)
3323 InsertConfigString(pDbgf, "TracingConfig", bstr);
3324
3325 BOOL fAllowTracingToAccessVM;
3326 hrc = pMachine->COMGETTER(AllowTracingToAccessVM)(&fAllowTracingToAccessVM); H();
3327 if (fAllowTracingToAccessVM)
3328 InsertConfigInteger(pPDM, "AllowTracingToAccessVM", 1);
3329
3330 /* Debugger console config. */
3331 PCFGMNODE pDbgc;
3332 InsertConfigNode(pRoot, "DBGC", &pDbgc);
3333
3334 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
3335 Utf8Str strVBoxHome = bstr;
3336 bstr.setNull();
3337 if (strVBoxHome.isNotEmpty())
3338 strVBoxHome.append("/");
3339 else
3340 {
3341 strVBoxHome = szHomeDir;
3342 strVBoxHome.append("/.vbox");
3343 }
3344
3345 Utf8Str strFile(strVBoxHome);
3346 strFile.append("dbgc-history");
3347 InsertConfigString(pDbgc, "HistoryFile", strFile);
3348
3349 strFile = strSettingsPath;
3350 strFile.append("dbgc-init");
3351 InsertConfigString(pDbgc, "LocalInitScript", strFile);
3352
3353 strFile = strVBoxHome;
3354 strFile.append("dbgc-init");
3355 InsertConfigString(pDbgc, "GlobalInitScript", strFile);
3356 }
3357 }
3358 catch (ConfigError &x)
3359 {
3360 // InsertConfig threw something:
3361 return x.m_vrc;
3362 }
3363 catch (HRESULT hrcXcpt)
3364 {
3365 AssertLogRelMsgFailedReturn(("hrc=%Rhrc\n", hrcXcpt), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
3366 }
3367
3368#ifdef VBOX_WITH_EXTPACK
3369 /*
3370 * Call the extension pack hooks if everything went well thus far.
3371 */
3372 if (RT_SUCCESS(rc))
3373 {
3374 pAlock->release();
3375 rc = mptrExtPackManager->i_callAllVmConfigureVmmHooks(this, pVM);
3376 pAlock->acquire();
3377 }
3378#endif
3379
3380 /*
3381 * Apply the CFGM overlay.
3382 */
3383 if (RT_SUCCESS(rc))
3384 rc = i_configCfgmOverlay(pRoot, virtualBox, pMachine);
3385
3386 /*
3387 * Dump all extradata API settings tweaks, both global and per VM.
3388 */
3389 if (RT_SUCCESS(rc))
3390 rc = i_configDumpAPISettingsTweaks(virtualBox, pMachine);
3391
3392#undef H
3393
3394 pAlock->release(); /* Avoid triggering the lock order inversion check. */
3395
3396 /*
3397 * Register VM state change handler.
3398 */
3399 int rc2 = VMR3AtStateRegister(pUVM, Console::i_vmstateChangeCallback, this);
3400 AssertRC(rc2);
3401 if (RT_SUCCESS(rc))
3402 rc = rc2;
3403
3404 /*
3405 * Register VM runtime error handler.
3406 */
3407 rc2 = VMR3AtRuntimeErrorRegister(pUVM, Console::i_atVMRuntimeErrorCallback, this);
3408 AssertRC(rc2);
3409 if (RT_SUCCESS(rc))
3410 rc = rc2;
3411
3412 pAlock->acquire();
3413
3414 LogFlowFunc(("vrc = %Rrc\n", rc));
3415 LogFlowFuncLeave();
3416
3417 return rc;
3418}
3419
3420/**
3421 * Retrieves an uint32_t value from the audio driver's extra data branch
3422 * (VBoxInternal2/Audio/DriverName/Value), or, if not found, use global branch
3423 * (VBoxInternal2/Audio/Value).
3424 *
3425 * The driver branch always supersedes the global branch.
3426 * If both branches are not found (empty), return the given default value.
3427 *
3428 * @return VBox status code.
3429 * @param pVirtualBox Pointer to IVirtualBox instance.
3430 * @param pMachine Pointer to IMachine instance.
3431 * @param pszDriverName Audio driver name to retrieve value for.
3432 * @param pszValue Value name to retrieve.
3433 * @param uDefault Default value to return if value not found / invalid.
3434 */
3435uint32_t Console::i_getAudioDriverValU32(IVirtualBox *pVirtualBox, IMachine *pMachine,
3436 const char *pszDriverName, const char *pszValue, uint32_t uDefault)
3437{
3438 Utf8Str strTmp;
3439
3440 Utf8StrFmt strPathDrv("VBoxInternal2/Audio/%s/%s", pszDriverName, pszValue);
3441 GetExtraDataBoth(pVirtualBox, pMachine, strPathDrv.c_str(), &strTmp);
3442 if (strTmp.isEmpty())
3443 {
3444 Utf8StrFmt strPathGlobal("VBoxInternal2/Audio/%s", pszValue);
3445 GetExtraDataBoth(pVirtualBox, pMachine, strPathGlobal.c_str(), &strTmp);
3446 if (strTmp.isNotEmpty())
3447 return strTmp.toUInt32();
3448 }
3449 else /* Return driver-specific value. */
3450 return strTmp.toUInt32();
3451
3452 return uDefault;
3453}
3454
3455/**
3456 * Configures an audio driver via CFGM by getting (optional) values from extra data.
3457 *
3458 * @return VBox status code.
3459 * @param pAudioAdapter Pointer to audio adapter instance. Needed for the driver's input / output configuration.
3460 * @param pVirtualBox Pointer to IVirtualBox instance.
3461 * @param pMachine Pointer to IMachine instance.
3462 * @param pLUN Pointer to CFGM node of LUN (the driver) to configure.
3463 * @param pszDrvName Name of the driver to configure.
3464 */
3465int Console::i_configAudioDriver(IAudioAdapter *pAudioAdapter, IVirtualBox *pVirtualBox, IMachine *pMachine,
3466 PCFGMNODE pLUN, const char *pszDrvName)
3467{
3468#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
3469
3470 HRESULT hrc;
3471
3472 Utf8Str strTmp;
3473 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/Audio/Debug/Enabled", &strTmp);
3474 const uint64_t fDebugEnabled = (strTmp.equalsIgnoreCase("true") || strTmp.equalsIgnoreCase("1")) ? 1 : 0;
3475
3476 BOOL fAudioEnabledIn = FALSE;
3477 hrc = pAudioAdapter->COMGETTER(EnabledIn)(&fAudioEnabledIn); H();
3478 BOOL fAudioEnabledOut = FALSE;
3479 hrc = pAudioAdapter->COMGETTER(EnabledOut)(&fAudioEnabledOut);
3480
3481 InsertConfigString(pLUN, "Driver", "AUDIO");
3482
3483 PCFGMNODE pCfg;
3484 InsertConfigNode(pLUN, "Config", &pCfg);
3485 InsertConfigString (pCfg, "DriverName", pszDrvName);
3486 InsertConfigInteger(pCfg, "InputEnabled", fAudioEnabledIn);
3487 InsertConfigInteger(pCfg, "OutputEnabled", fAudioEnabledOut);
3488
3489 if (fDebugEnabled)
3490 {
3491 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
3492
3493 Utf8Str strDebugPathOut;
3494 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/Audio/Debug/PathOut", &strDebugPathOut);
3495 InsertConfigString(pCfg, "DebugPathOut", strDebugPathOut.c_str());
3496 }
3497
3498 InsertConfigInteger(pCfg, "PeriodSizeMs",
3499 i_getAudioDriverValU32(pVirtualBox, pMachine, pszDrvName, "PeriodSizeMs", 0 /* Default */));
3500 InsertConfigInteger(pCfg, "BufferSizeMs",
3501 i_getAudioDriverValU32(pVirtualBox, pMachine, pszDrvName, "BufferSizeMs", 0 /* Default */));
3502 InsertConfigInteger(pCfg, "PreBufferSizeMs",
3503 i_getAudioDriverValU32(pVirtualBox, pMachine, pszDrvName, "PreBufferSizeMs", UINT32_MAX /* Default */));
3504
3505 PCFGMNODE pLunL1;
3506 InsertConfigNode(pLUN, "AttachedDriver", &pLunL1);
3507
3508 InsertConfigNode(pLunL1, "Config", &pCfg);
3509
3510 Bstr bstrTmp;
3511 hrc = pMachine->COMGETTER(Name)(bstrTmp.asOutParam()); H();
3512 InsertConfigString(pCfg, "StreamName", bstrTmp);
3513
3514 InsertConfigString(pLunL1, "Driver", pszDrvName);
3515
3516 LogFlowFunc(("szDrivName=%s, hrc=%Rhrc\n", pszDrvName, hrc));
3517 return hrc;
3518
3519#undef H
3520}
3521
3522/**
3523 * Applies the CFGM overlay as specified by VBoxInternal/XXX extra data
3524 * values.
3525 *
3526 * @returns VBox status code.
3527 * @param pRoot The root of the configuration tree.
3528 * @param pVirtualBox Pointer to the IVirtualBox interface.
3529 * @param pMachine Pointer to the IMachine interface.
3530 */
3531/* static */
3532int Console::i_configCfgmOverlay(PCFGMNODE pRoot, IVirtualBox *pVirtualBox, IMachine *pMachine)
3533{
3534 /*
3535 * CFGM overlay handling.
3536 *
3537 * Here we check the extra data entries for CFGM values
3538 * and create the nodes and insert the values on the fly. Existing
3539 * values will be removed and reinserted. CFGM is typed, so by default
3540 * we will guess whether it's a string or an integer (byte arrays are
3541 * not currently supported). It's possible to override this autodetection
3542 * by adding "string:", "integer:" or "bytes:" (future).
3543 *
3544 * We first perform a run on global extra data, then on the machine
3545 * extra data to support global settings with local overrides.
3546 */
3547 int rc = VINF_SUCCESS;
3548 try
3549 {
3550 /** @todo add support for removing nodes and byte blobs. */
3551 /*
3552 * Get the next key
3553 */
3554 SafeArray<BSTR> aGlobalExtraDataKeys;
3555 SafeArray<BSTR> aMachineExtraDataKeys;
3556 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
3557 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
3558
3559 // remember the no. of global values so we can call the correct method below
3560 size_t cGlobalValues = aGlobalExtraDataKeys.size();
3561
3562 hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
3563 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
3564
3565 // build a combined list from global keys...
3566 std::list<Utf8Str> llExtraDataKeys;
3567
3568 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); ++i)
3569 llExtraDataKeys.push_back(Utf8Str(aGlobalExtraDataKeys[i]));
3570 // ... and machine keys
3571 for (size_t i = 0; i < aMachineExtraDataKeys.size(); ++i)
3572 llExtraDataKeys.push_back(Utf8Str(aMachineExtraDataKeys[i]));
3573
3574 size_t i2 = 0;
3575 for (std::list<Utf8Str>::const_iterator it = llExtraDataKeys.begin();
3576 it != llExtraDataKeys.end();
3577 ++it, ++i2)
3578 {
3579 const Utf8Str &strKey = *it;
3580
3581 /*
3582 * We only care about keys starting with "VBoxInternal/" (skip "G:" or "M:")
3583 */
3584 if (!strKey.startsWith("VBoxInternal/"))
3585 continue;
3586
3587 const char *pszExtraDataKey = strKey.c_str() + sizeof("VBoxInternal/") - 1;
3588
3589 // get the value
3590 Bstr bstrExtraDataValue;
3591 if (i2 < cGlobalValues)
3592 // this is still one of the global values:
3593 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
3594 bstrExtraDataValue.asOutParam());
3595 else
3596 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
3597 bstrExtraDataValue.asOutParam());
3598 if (FAILED(hrc))
3599 LogRel(("Warning: Cannot get extra data key %s, rc = %Rhrc\n", strKey.c_str(), hrc));
3600
3601 /*
3602 * The key will be in the format "Node1/Node2/Value" or simply "Value".
3603 * Split the two and get the node, delete the value and create the node
3604 * if necessary.
3605 */
3606 PCFGMNODE pNode;
3607 const char *pszCFGMValueName = strrchr(pszExtraDataKey, '/');
3608 if (pszCFGMValueName)
3609 {
3610 /* terminate the node and advance to the value (Utf8Str might not
3611 offically like this but wtf) */
3612 *(char*)pszCFGMValueName = '\0';
3613 ++pszCFGMValueName;
3614
3615 /* does the node already exist? */
3616 pNode = CFGMR3GetChild(pRoot, pszExtraDataKey);
3617 if (pNode)
3618 CFGMR3RemoveValue(pNode, pszCFGMValueName);
3619 else
3620 {
3621 /* create the node */
3622 rc = CFGMR3InsertNode(pRoot, pszExtraDataKey, &pNode);
3623 if (RT_FAILURE(rc))
3624 {
3625 AssertLogRelMsgRC(rc, ("failed to insert node '%s'\n", pszExtraDataKey));
3626 continue;
3627 }
3628 Assert(pNode);
3629 }
3630 }
3631 else
3632 {
3633 /* root value (no node path). */
3634 pNode = pRoot;
3635 pszCFGMValueName = pszExtraDataKey;
3636 pszExtraDataKey--;
3637 CFGMR3RemoveValue(pNode, pszCFGMValueName);
3638 }
3639
3640 /*
3641 * Now let's have a look at the value.
3642 * Empty strings means that we should remove the value, which we've
3643 * already done above.
3644 */
3645 Utf8Str strCFGMValueUtf8(bstrExtraDataValue);
3646 if (!strCFGMValueUtf8.isEmpty())
3647 {
3648 uint64_t u64Value;
3649
3650 /* check for type prefix first. */
3651 if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("string:")))
3652 InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8.c_str() + sizeof("string:") - 1);
3653 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("integer:")))
3654 {
3655 rc = RTStrToUInt64Full(strCFGMValueUtf8.c_str() + sizeof("integer:") - 1, 0, &u64Value);
3656 if (RT_SUCCESS(rc))
3657 rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
3658 }
3659 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("bytes:")))
3660 {
3661 char const *pszBase64 = strCFGMValueUtf8.c_str() + sizeof("bytes:") - 1;
3662 ssize_t cbValue = RTBase64DecodedSize(pszBase64, NULL);
3663 if (cbValue > 0)
3664 {
3665 void *pvBytes = RTMemTmpAlloc(cbValue);
3666 if (pvBytes)
3667 {
3668 rc = RTBase64Decode(pszBase64, pvBytes, cbValue, NULL, NULL);
3669 if (RT_SUCCESS(rc))
3670 rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, pvBytes, cbValue);
3671 RTMemTmpFree(pvBytes);
3672 }
3673 else
3674 rc = VERR_NO_TMP_MEMORY;
3675 }
3676 else if (cbValue == 0)
3677 rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, NULL, 0);
3678 else
3679 rc = VERR_INVALID_BASE64_ENCODING;
3680 }
3681 /* auto detect type. */
3682 else if (RT_SUCCESS(RTStrToUInt64Full(strCFGMValueUtf8.c_str(), 0, &u64Value)))
3683 rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
3684 else
3685 InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8);
3686 AssertLogRelMsgRCBreak(rc, ("failed to insert CFGM value '%s' to key '%s'\n",
3687 strCFGMValueUtf8.c_str(), pszExtraDataKey));
3688 }
3689 }
3690 }
3691 catch (ConfigError &x)
3692 {
3693 // InsertConfig threw something:
3694 return x.m_vrc;
3695 }
3696 return rc;
3697}
3698
3699/**
3700 * Dumps the API settings tweaks as specified by VBoxInternal2/XXX extra data
3701 * values.
3702 *
3703 * @returns VBox status code.
3704 * @param pVirtualBox Pointer to the IVirtualBox interface.
3705 * @param pMachine Pointer to the IMachine interface.
3706 */
3707/* static */
3708int Console::i_configDumpAPISettingsTweaks(IVirtualBox *pVirtualBox, IMachine *pMachine)
3709{
3710 {
3711 SafeArray<BSTR> aGlobalExtraDataKeys;
3712 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
3713 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
3714 bool hasKey = false;
3715 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); i++)
3716 {
3717 Utf8Str strKey(aGlobalExtraDataKeys[i]);
3718 if (!strKey.startsWith("VBoxInternal2/"))
3719 continue;
3720
3721 Bstr bstrValue;
3722 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
3723 bstrValue.asOutParam());
3724 if (FAILED(hrc))
3725 continue;
3726 if (!hasKey)
3727 LogRel(("Global extradata API settings:\n"));
3728 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
3729 hasKey = true;
3730 }
3731 }
3732
3733 {
3734 SafeArray<BSTR> aMachineExtraDataKeys;
3735 HRESULT hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
3736 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
3737 bool hasKey = false;
3738 for (size_t i = 0; i < aMachineExtraDataKeys.size(); i++)
3739 {
3740 Utf8Str strKey(aMachineExtraDataKeys[i]);
3741 if (!strKey.startsWith("VBoxInternal2/"))
3742 continue;
3743
3744 Bstr bstrValue;
3745 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
3746 bstrValue.asOutParam());
3747 if (FAILED(hrc))
3748 continue;
3749 if (!hasKey)
3750 LogRel(("Per-VM extradata API settings:\n"));
3751 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
3752 hasKey = true;
3753 }
3754 }
3755
3756 return VINF_SUCCESS;
3757}
3758
3759int Console::i_configGraphicsController(PCFGMNODE pDevices,
3760 const GraphicsControllerType_T enmGraphicsController,
3761 BusAssignmentManager *pBusMgr,
3762 const ComPtr<IMachine> &ptrMachine,
3763 const ComPtr<IGraphicsAdapter> &ptrGraphicsAdapter,
3764 const ComPtr<IBIOSSettings> &ptrBiosSettings,
3765 bool fHMEnabled)
3766{
3767 // InsertConfig* throws
3768 try
3769 {
3770 PCFGMNODE pDev, pInst, pCfg, pLunL0;
3771 HRESULT hrc;
3772 Bstr bstr;
3773 const char *pcszDevice = "vga";
3774
3775#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
3776 InsertConfigNode(pDevices, pcszDevice, &pDev);
3777 InsertConfigNode(pDev, "0", &pInst);
3778 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3779
3780 hrc = pBusMgr->assignPCIDevice(pcszDevice, pInst); H();
3781 InsertConfigNode(pInst, "Config", &pCfg);
3782 ULONG cVRamMBs;
3783 hrc = ptrGraphicsAdapter->COMGETTER(VRAMSize)(&cVRamMBs); H();
3784 InsertConfigInteger(pCfg, "VRamSize", cVRamMBs * _1M);
3785 ULONG cMonitorCount;
3786 hrc = ptrGraphicsAdapter->COMGETTER(MonitorCount)(&cMonitorCount); H();
3787 InsertConfigInteger(pCfg, "MonitorCount", cMonitorCount);
3788#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
3789 InsertConfigInteger(pCfg, "R0Enabled", fHMEnabled);
3790#else
3791 NOREF(fHMEnabled);
3792#endif
3793 BOOL f3DEnabled;
3794 hrc = ptrGraphicsAdapter->COMGETTER(Accelerate3DEnabled)(&f3DEnabled); H();
3795 InsertConfigInteger(pCfg, "3DEnabled", f3DEnabled);
3796
3797 i_attachStatusDriver(pInst, &mapCrOglLed, 0, 0, NULL, NULL, 0);
3798
3799#ifdef VBOX_WITH_VMSVGA
3800 if ( enmGraphicsController == GraphicsControllerType_VMSVGA
3801 || enmGraphicsController == GraphicsControllerType_VBoxSVGA)
3802 {
3803 InsertConfigInteger(pCfg, "VMSVGAEnabled", true);
3804 if (enmGraphicsController == GraphicsControllerType_VMSVGA)
3805 {
3806 InsertConfigInteger(pCfg, "VMSVGAPciBarLayout", true);
3807 InsertConfigInteger(pCfg, "VMSVGAPciId", true);
3808 }
3809# ifdef VBOX_WITH_VMSVGA3D
3810 InsertConfigInteger(pCfg, "VMSVGA3dEnabled", f3DEnabled);
3811# else
3812 LogRel(("VMSVGA3d not available in this build!\n"));
3813# endif /* VBOX_WITH_VMSVGA3D */
3814 }
3815#else
3816 RT_NOREF(enmGraphicsController);
3817#endif /* VBOX_WITH_VMSVGA */
3818
3819 /* Custom VESA mode list */
3820 unsigned cModes = 0;
3821 for (unsigned iMode = 1; iMode <= 16; ++iMode)
3822 {
3823 char szExtraDataKey[sizeof("CustomVideoModeXX")];
3824 RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%u", iMode);
3825 hrc = ptrMachine->GetExtraData(Bstr(szExtraDataKey).raw(), bstr.asOutParam()); H();
3826 if (bstr.isEmpty())
3827 break;
3828 InsertConfigString(pCfg, szExtraDataKey, bstr);
3829 ++cModes;
3830 }
3831 InsertConfigInteger(pCfg, "CustomVideoModes", cModes);
3832
3833 /* VESA height reduction */
3834 ULONG ulHeightReduction;
3835 IFramebuffer *pFramebuffer = NULL;
3836 hrc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
3837 if (SUCCEEDED(hrc) && pFramebuffer)
3838 {
3839 hrc = pFramebuffer->COMGETTER(HeightReduction)(&ulHeightReduction); H();
3840 pFramebuffer->Release();
3841 pFramebuffer = NULL;
3842 }
3843 else
3844 {
3845 /* If framebuffer is not available, there is no height reduction. */
3846 ulHeightReduction = 0;
3847 }
3848 InsertConfigInteger(pCfg, "HeightReduction", ulHeightReduction);
3849
3850 /*
3851 * BIOS logo
3852 */
3853 BOOL fFadeIn;
3854 hrc = ptrBiosSettings->COMGETTER(LogoFadeIn)(&fFadeIn); H();
3855 InsertConfigInteger(pCfg, "FadeIn", fFadeIn ? 1 : 0);
3856 BOOL fFadeOut;
3857 hrc = ptrBiosSettings->COMGETTER(LogoFadeOut)(&fFadeOut); H();
3858 InsertConfigInteger(pCfg, "FadeOut", fFadeOut ? 1: 0);
3859 ULONG logoDisplayTime;
3860 hrc = ptrBiosSettings->COMGETTER(LogoDisplayTime)(&logoDisplayTime); H();
3861 InsertConfigInteger(pCfg, "LogoTime", logoDisplayTime);
3862 Bstr logoImagePath;
3863 hrc = ptrBiosSettings->COMGETTER(LogoImagePath)(logoImagePath.asOutParam()); H();
3864 InsertConfigString(pCfg, "LogoFile", Utf8Str(!logoImagePath.isEmpty() ? logoImagePath : "") );
3865
3866 /*
3867 * Boot menu
3868 */
3869 BIOSBootMenuMode_T eBootMenuMode;
3870 int iShowBootMenu;
3871 hrc = ptrBiosSettings->COMGETTER(BootMenuMode)(&eBootMenuMode); H();
3872 switch (eBootMenuMode)
3873 {
3874 case BIOSBootMenuMode_Disabled: iShowBootMenu = 0; break;
3875 case BIOSBootMenuMode_MenuOnly: iShowBootMenu = 1; break;
3876 default: iShowBootMenu = 2; break;
3877 }
3878 InsertConfigInteger(pCfg, "ShowBootMenu", iShowBootMenu);
3879
3880 /* Attach the display. */
3881 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3882 InsertConfigString(pLunL0, "Driver", "MainDisplay");
3883 InsertConfigNode(pLunL0, "Config", &pCfg);
3884 Display *pDisplay = mDisplay;
3885 InsertConfigInteger(pCfg, "Object", (uintptr_t)pDisplay);
3886 }
3887 catch (ConfigError &x)
3888 {
3889 // InsertConfig threw something:
3890 return x.m_vrc;
3891 }
3892
3893#undef H
3894
3895 return VINF_SUCCESS;
3896}
3897
3898
3899/**
3900 * Ellipsis to va_list wrapper for calling setVMRuntimeErrorCallback.
3901 */
3902void Console::i_atVMRuntimeErrorCallbackF(uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)
3903{
3904 va_list va;
3905 va_start(va, pszFormat);
3906 i_atVMRuntimeErrorCallback(NULL, this, fFlags, pszErrorId, pszFormat, va);
3907 va_end(va);
3908}
3909
3910/* XXX introduce RT format specifier */
3911static uint64_t formatDiskSize(uint64_t u64Size, const char **pszUnit)
3912{
3913 if (u64Size > INT64_C(5000)*_1G)
3914 {
3915 *pszUnit = "TB";
3916 return u64Size / _1T;
3917 }
3918 else if (u64Size > INT64_C(5000)*_1M)
3919 {
3920 *pszUnit = "GB";
3921 return u64Size / _1G;
3922 }
3923 else
3924 {
3925 *pszUnit = "MB";
3926 return u64Size / _1M;
3927 }
3928}
3929
3930/**
3931 * Checks the location of the given medium for known bugs affecting the usage
3932 * of the host I/O cache setting.
3933 *
3934 * @returns VBox status code.
3935 * @param pMedium The medium to check.
3936 * @param pfUseHostIOCache Where to store the suggested host I/O cache setting.
3937 */
3938int Console::i_checkMediumLocation(IMedium *pMedium, bool *pfUseHostIOCache)
3939{
3940#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
3941 /*
3942 * Some sanity checks.
3943 */
3944 RT_NOREF(pfUseHostIOCache);
3945 ComPtr<IMediumFormat> pMediumFormat;
3946 HRESULT hrc = pMedium->COMGETTER(MediumFormat)(pMediumFormat.asOutParam()); H();
3947 ULONG uCaps = 0;
3948 com::SafeArray <MediumFormatCapabilities_T> mediumFormatCap;
3949 hrc = pMediumFormat->COMGETTER(Capabilities)(ComSafeArrayAsOutParam(mediumFormatCap)); H();
3950
3951 for (ULONG j = 0; j < mediumFormatCap.size(); j++)
3952 uCaps |= mediumFormatCap[j];
3953
3954 if (uCaps & MediumFormatCapabilities_File)
3955 {
3956 Bstr strFile;
3957 hrc = pMedium->COMGETTER(Location)(strFile.asOutParam()); H();
3958 Utf8Str utfFile = Utf8Str(strFile);
3959 Bstr strSnap;
3960 ComPtr<IMachine> pMachine = i_machine();
3961 hrc = pMachine->COMGETTER(SnapshotFolder)(strSnap.asOutParam()); H();
3962 Utf8Str utfSnap = Utf8Str(strSnap);
3963 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
3964 RTFSTYPE enmFsTypeSnap = RTFSTYPE_UNKNOWN;
3965 int rc2 = RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
3966 AssertMsgRCReturn(rc2, ("Querying the file type of '%s' failed!\n", utfFile.c_str()), rc2);
3967 /* Ignore the error code. On error, the file system type is still 'unknown' so
3968 * none of the following paths are taken. This can happen for new VMs which
3969 * still don't have a snapshot folder. */
3970 (void)RTFsQueryType(utfSnap.c_str(), &enmFsTypeSnap);
3971 if (!mfSnapshotFolderDiskTypeShown)
3972 {
3973 LogRel(("File system of '%s' (snapshots) is %s\n",
3974 utfSnap.c_str(), RTFsTypeName(enmFsTypeSnap)));
3975 mfSnapshotFolderDiskTypeShown = true;
3976 }
3977 LogRel(("File system of '%s' is %s\n", utfFile.c_str(), RTFsTypeName(enmFsTypeFile)));
3978 LONG64 i64Size;
3979 hrc = pMedium->COMGETTER(LogicalSize)(&i64Size); H();
3980#ifdef RT_OS_WINDOWS
3981 if ( enmFsTypeFile == RTFSTYPE_FAT
3982 && i64Size >= _4G)
3983 {
3984 const char *pszUnit;
3985 uint64_t u64Print = formatDiskSize((uint64_t)i64Size, &pszUnit);
3986 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
3987 N_("The medium '%ls' has a logical size of %RU64%s "
3988 "but the file system the medium is located on seems "
3989 "to be FAT(32) which cannot handle files bigger than 4GB.\n"
3990 "We strongly recommend to put all your virtual disk images and "
3991 "the snapshot folder onto an NTFS partition"),
3992 strFile.raw(), u64Print, pszUnit);
3993 }
3994#else /* !RT_OS_WINDOWS */
3995 if ( enmFsTypeFile == RTFSTYPE_FAT
3996 || enmFsTypeFile == RTFSTYPE_EXT
3997 || enmFsTypeFile == RTFSTYPE_EXT2
3998 || enmFsTypeFile == RTFSTYPE_EXT3
3999 || enmFsTypeFile == RTFSTYPE_EXT4)
4000 {
4001 RTFILE file;
4002 int rc = RTFileOpen(&file, utfFile.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
4003 if (RT_SUCCESS(rc))
4004 {
4005 RTFOFF maxSize;
4006 /* Careful: This function will work only on selected local file systems! */
4007 rc = RTFileQueryMaxSizeEx(file, &maxSize);
4008 RTFileClose(file);
4009 if ( RT_SUCCESS(rc)
4010 && maxSize > 0
4011 && i64Size > (LONG64)maxSize)
4012 {
4013 const char *pszUnitSiz;
4014 const char *pszUnitMax;
4015 uint64_t u64PrintSiz = formatDiskSize((LONG64)i64Size, &pszUnitSiz);
4016 uint64_t u64PrintMax = formatDiskSize(maxSize, &pszUnitMax);
4017 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected", /* <= not exact but ... */
4018 N_("The medium '%ls' has a logical size of %RU64%s "
4019 "but the file system the medium is located on can "
4020 "only handle files up to %RU64%s in theory.\n"
4021 "We strongly recommend to put all your virtual disk "
4022 "images and the snapshot folder onto a proper "
4023 "file system (e.g. ext3) with a sufficient size"),
4024 strFile.raw(), u64PrintSiz, pszUnitSiz, u64PrintMax, pszUnitMax);
4025 }
4026 }
4027 }
4028#endif /* !RT_OS_WINDOWS */
4029
4030 /*
4031 * Snapshot folder:
4032 * Here we test only for a FAT partition as we had to create a dummy file otherwise
4033 */
4034 if ( enmFsTypeSnap == RTFSTYPE_FAT
4035 && i64Size >= _4G
4036 && !mfSnapshotFolderSizeWarningShown)
4037 {
4038 const char *pszUnit;
4039 uint64_t u64Print = formatDiskSize(i64Size, &pszUnit);
4040 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
4041#ifdef RT_OS_WINDOWS
4042 N_("The snapshot folder of this VM '%ls' seems to be located on "
4043 "a FAT(32) file system. The logical size of the medium '%ls' "
4044 "(%RU64%s) is bigger than the maximum file size this file "
4045 "system can handle (4GB).\n"
4046 "We strongly recommend to put all your virtual disk images and "
4047 "the snapshot folder onto an NTFS partition"),
4048#else
4049 N_("The snapshot folder of this VM '%ls' seems to be located on "
4050 "a FAT(32) file system. The logical size of the medium '%ls' "
4051 "(%RU64%s) is bigger than the maximum file size this file "
4052 "system can handle (4GB).\n"
4053 "We strongly recommend to put all your virtual disk images and "
4054 "the snapshot folder onto a proper file system (e.g. ext3)"),
4055#endif
4056 strSnap.raw(), strFile.raw(), u64Print, pszUnit);
4057 /* Show this particular warning only once */
4058 mfSnapshotFolderSizeWarningShown = true;
4059 }
4060
4061#ifdef RT_OS_LINUX
4062 /*
4063 * Ext4 bug: Check if the host I/O cache is disabled and the disk image is located
4064 * on an ext4 partition.
4065 * This bug apparently applies to the XFS file system as well.
4066 * Linux 2.6.36 is known to be fixed (tested with 2.6.36-rc4).
4067 */
4068
4069 char szOsRelease[128];
4070 int rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOsRelease, sizeof(szOsRelease));
4071 bool fKernelHasODirectBug = RT_FAILURE(rc)
4072 || (RTStrVersionCompare(szOsRelease, "2.6.36-rc4") < 0);
4073
4074 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
4075 && !*pfUseHostIOCache
4076 && fKernelHasODirectBug)
4077 {
4078 if ( enmFsTypeFile == RTFSTYPE_EXT4
4079 || enmFsTypeFile == RTFSTYPE_XFS)
4080 {
4081 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
4082 N_("The host I/O cache for at least one controller is disabled "
4083 "and the medium '%ls' for this VM "
4084 "is located on an %s partition. There is a known Linux "
4085 "kernel bug which can lead to the corruption of the virtual "
4086 "disk image under these conditions.\n"
4087 "Either enable the host I/O cache permanently in the VM "
4088 "settings or put the disk image and the snapshot folder "
4089 "onto a different file system.\n"
4090 "The host I/O cache will now be enabled for this medium"),
4091 strFile.raw(), enmFsTypeFile == RTFSTYPE_EXT4 ? "ext4" : "xfs");
4092 *pfUseHostIOCache = true;
4093 }
4094 else if ( ( enmFsTypeSnap == RTFSTYPE_EXT4
4095 || enmFsTypeSnap == RTFSTYPE_XFS)
4096 && !mfSnapshotFolderExt4WarningShown)
4097 {
4098 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
4099 N_("The host I/O cache for at least one controller is disabled "
4100 "and the snapshot folder for this VM "
4101 "is located on an %s partition. There is a known Linux "
4102 "kernel bug which can lead to the corruption of the virtual "
4103 "disk image under these conditions.\n"
4104 "Either enable the host I/O cache permanently in the VM "
4105 "settings or put the disk image and the snapshot folder "
4106 "onto a different file system.\n"
4107 "The host I/O cache will now be enabled for this medium"),
4108 enmFsTypeSnap == RTFSTYPE_EXT4 ? "ext4" : "xfs");
4109 *pfUseHostIOCache = true;
4110 mfSnapshotFolderExt4WarningShown = true;
4111 }
4112 }
4113
4114 /*
4115 * 2.6.18 bug: Check if the host I/O cache is disabled and the host is running
4116 * Linux 2.6.18. See @bugref{8690}. Apparently the same problem as
4117 * documented in https://lkml.org/lkml/2007/2/1/14. We saw such
4118 * kernel oopses on Linux 2.6.18-416.el5. We don't know when this
4119 * was fixed but we _know_ that 2.6.18 EL5 kernels are affected.
4120 */
4121 bool fKernelAsyncUnreliable = RT_FAILURE(rc)
4122 || (RTStrVersionCompare(szOsRelease, "2.6.19") < 0);
4123 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
4124 && !*pfUseHostIOCache
4125 && fKernelAsyncUnreliable)
4126 {
4127 i_atVMRuntimeErrorCallbackF(0, "Linux2618TooOld",
4128 N_("The host I/O cache for at least one controller is disabled. "
4129 "There is a known Linux kernel bug which can lead to kernel "
4130 "oopses under heavy load. To our knowledge this bug affects "
4131 "all 2.6.18 kernels.\n"
4132 "Either enable the host I/O cache permanently in the VM "
4133 "settings or switch to a newer host kernel.\n"
4134 "The host I/O cache will now be enabled for this medium"));
4135 *pfUseHostIOCache = true;
4136 }
4137#endif
4138 }
4139#undef H
4140
4141 return VINF_SUCCESS;
4142}
4143
4144/**
4145 * Unmounts the specified medium from the specified device.
4146 *
4147 * @returns VBox status code.
4148 * @param pUVM The usermode VM handle.
4149 * @param enmBus The storage bus.
4150 * @param enmDevType The device type.
4151 * @param pcszDevice The device emulation.
4152 * @param uInstance Instance of the device.
4153 * @param uLUN The LUN on the device.
4154 * @param fForceUnmount Whether to force unmounting.
4155 */
4156int Console::i_unmountMediumFromGuest(PUVM pUVM, StorageBus_T enmBus, DeviceType_T enmDevType,
4157 const char *pcszDevice, unsigned uInstance, unsigned uLUN,
4158 bool fForceUnmount)
4159{
4160 /* Unmount existing media only for floppy and DVD drives. */
4161 int rc = VINF_SUCCESS;
4162 PPDMIBASE pBase;
4163 if (enmBus == StorageBus_USB)
4164 rc = PDMR3UsbQueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
4165 else if ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI || enmBus == StorageBus_VirtioSCSI)
4166 || (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD))
4167 rc = PDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
4168 else /* IDE or Floppy */
4169 rc = PDMR3QueryLun(pUVM, pcszDevice, uInstance, uLUN, &pBase);
4170
4171 if (RT_FAILURE(rc))
4172 {
4173 if (rc == VERR_PDM_LUN_NOT_FOUND || rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4174 rc = VINF_SUCCESS;
4175 AssertRC(rc);
4176 }
4177 else
4178 {
4179 PPDMIMOUNT pIMount = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMOUNT);
4180 AssertReturn(pIMount, VERR_INVALID_POINTER);
4181
4182 /* Unmount the media (but do not eject the medium!) */
4183 rc = pIMount->pfnUnmount(pIMount, fForceUnmount, false /*=fEject*/);
4184 if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
4185 rc = VINF_SUCCESS;
4186 /* for example if the medium is locked */
4187 else if (RT_FAILURE(rc))
4188 return rc;
4189 }
4190
4191 return rc;
4192}
4193
4194/**
4195 * Removes the currently attached medium driver form the specified device
4196 * taking care of the controlelr specific configs wrt. to the attached driver chain.
4197 *
4198 * @returns VBox status code.
4199 * @param pCtlInst The controler instance node in the CFGM tree.
4200 * @param pcszDevice The device name.
4201 * @param uInstance The device instance.
4202 * @param uLUN The device LUN.
4203 * @param enmBus The storage bus.
4204 * @param fAttachDetach Flag whether this is a change while the VM is running
4205 * @param fHotplug Flag whether the guest should be notified about the device change.
4206 * @param fForceUnmount Flag whether to force unmounting the medium even if it is locked.
4207 * @param pUVM The usermode VM handle.
4208 * @param enmDevType The device type.
4209 * @param ppLunL0 Where to store the node to attach the new config to on success.
4210 */
4211int Console::i_removeMediumDriverFromVm(PCFGMNODE pCtlInst,
4212 const char *pcszDevice,
4213 unsigned uInstance,
4214 unsigned uLUN,
4215 StorageBus_T enmBus,
4216 bool fAttachDetach,
4217 bool fHotplug,
4218 bool fForceUnmount,
4219 PUVM pUVM,
4220 DeviceType_T enmDevType,
4221 PCFGMNODE *ppLunL0)
4222{
4223 int rc = VINF_SUCCESS;
4224 bool fAddLun = false;
4225
4226 /* First check if the LUN already exists. */
4227 PCFGMNODE pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
4228 AssertReturn(!VALID_PTR(pLunL0) || fAttachDetach, VERR_INTERNAL_ERROR);
4229
4230 if (pLunL0)
4231 {
4232 /*
4233 * Unmount the currently mounted medium if we don't just hot remove the
4234 * complete device (SATA) and it supports unmounting (DVD).
4235 */
4236 if ( (enmDevType != DeviceType_HardDisk)
4237 && !fHotplug)
4238 {
4239 rc = i_unmountMediumFromGuest(pUVM, enmBus, enmDevType, pcszDevice,
4240 uInstance, uLUN, fForceUnmount);
4241 if (RT_FAILURE(rc))
4242 return rc;
4243 }
4244
4245 /*
4246 * Don't detach the SCSI driver when unmounting the current medium
4247 * (we are not ripping out the device but only eject the medium).
4248 */
4249 char *pszDriverDetach = NULL;
4250 if ( !fHotplug
4251 && ( (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD)
4252 || enmBus == StorageBus_SAS
4253 || enmBus == StorageBus_SCSI
4254 || enmBus == StorageBus_VirtioSCSI
4255 || enmBus == StorageBus_USB))
4256 {
4257 /* Get the current attached driver we have to detach. */
4258 PCFGMNODE pDrvLun = CFGMR3GetChildF(pCtlInst, "LUN#%u/AttachedDriver/", uLUN);
4259 if (pDrvLun)
4260 {
4261 char szDriver[128];
4262 RT_ZERO(szDriver);
4263 rc = CFGMR3QueryString(pDrvLun, "Driver", &szDriver[0], sizeof(szDriver));
4264 if (RT_SUCCESS(rc))
4265 pszDriverDetach = RTStrDup(&szDriver[0]);
4266
4267 pLunL0 = pDrvLun;
4268 }
4269 }
4270
4271 if (enmBus == StorageBus_USB)
4272 rc = PDMR3UsbDriverDetach(pUVM, pcszDevice, uInstance, uLUN,
4273 pszDriverDetach, 0 /* iOccurence */,
4274 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
4275 else
4276 rc = PDMR3DriverDetach(pUVM, pcszDevice, uInstance, uLUN,
4277 pszDriverDetach, 0 /* iOccurence */,
4278 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
4279
4280 if (pszDriverDetach)
4281 {
4282 RTStrFree(pszDriverDetach);
4283 /* Remove the complete node and create new for the new config. */
4284 CFGMR3RemoveNode(pLunL0);
4285 pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
4286 if (pLunL0)
4287 {
4288 try
4289 {
4290 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4291 }
4292 catch (ConfigError &x)
4293 {
4294 // InsertConfig threw something:
4295 return x.m_vrc;
4296 }
4297 }
4298 }
4299 if (rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4300 rc = VINF_SUCCESS;
4301 AssertRCReturn(rc, rc);
4302
4303 /*
4304 * Don't remove the LUN except for IDE/floppy/NVMe (which connects directly to the medium driver
4305 * even for DVD devices) or if there is a hotplug event which rips out the complete device.
4306 */
4307 if ( fHotplug
4308 || enmBus == StorageBus_IDE
4309 || enmBus == StorageBus_Floppy
4310 || enmBus == StorageBus_PCIe
4311 || (enmBus == StorageBus_SATA && enmDevType != DeviceType_DVD))
4312 {
4313 fAddLun = true;
4314 CFGMR3RemoveNode(pLunL0);
4315 }
4316 }
4317 else
4318 fAddLun = true;
4319
4320 try
4321 {
4322 if (fAddLun)
4323 InsertConfigNode(pCtlInst, Utf8StrFmt("LUN#%u", uLUN).c_str(), &pLunL0);
4324 }
4325 catch (ConfigError &x)
4326 {
4327 // InsertConfig threw something:
4328 return x.m_vrc;
4329 }
4330
4331 if (ppLunL0)
4332 *ppLunL0 = pLunL0;
4333
4334 return rc;
4335}
4336
4337int Console::i_configMediumAttachment(const char *pcszDevice,
4338 unsigned uInstance,
4339 StorageBus_T enmBus,
4340 bool fUseHostIOCache,
4341 bool fBuiltinIOCache,
4342 bool fInsertDiskIntegrityDrv,
4343 bool fSetupMerge,
4344 unsigned uMergeSource,
4345 unsigned uMergeTarget,
4346 IMediumAttachment *pMediumAtt,
4347 MachineState_T aMachineState,
4348 HRESULT *phrc,
4349 bool fAttachDetach,
4350 bool fForceUnmount,
4351 bool fHotplug,
4352 PUVM pUVM,
4353 DeviceType_T *paLedDevType,
4354 PCFGMNODE *ppLunL0)
4355{
4356 // InsertConfig* throws
4357 try
4358 {
4359 int rc = VINF_SUCCESS;
4360 HRESULT hrc;
4361 Bstr bstr;
4362 PCFGMNODE pCtlInst = NULL;
4363
4364// #define RC_CHECK() AssertMsgReturn(RT_SUCCESS(rc), ("rc=%Rrc\n", rc), rc)
4365#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4366
4367 LONG lDev;
4368 hrc = pMediumAtt->COMGETTER(Device)(&lDev); H();
4369 LONG lPort;
4370 hrc = pMediumAtt->COMGETTER(Port)(&lPort); H();
4371 DeviceType_T lType;
4372 hrc = pMediumAtt->COMGETTER(Type)(&lType); H();
4373 BOOL fNonRotational;
4374 hrc = pMediumAtt->COMGETTER(NonRotational)(&fNonRotational); H();
4375 BOOL fDiscard;
4376 hrc = pMediumAtt->COMGETTER(Discard)(&fDiscard); H();
4377
4378 if (lType == DeviceType_DVD)
4379 fInsertDiskIntegrityDrv = false;
4380
4381 unsigned uLUN;
4382 PCFGMNODE pLunL0 = NULL;
4383 hrc = Console::i_storageBusPortDeviceToLun(enmBus, lPort, lDev, uLUN); H();
4384
4385 /* Determine the base path for the device instance. */
4386 if (enmBus != StorageBus_USB)
4387 pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "Devices/%s/%u/", pcszDevice, uInstance);
4388 else
4389 {
4390 /* If we hotplug a USB device create a new CFGM tree. */
4391 if (!fHotplug)
4392 pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "USB/%s/", pcszDevice);
4393 else
4394 pCtlInst = CFGMR3CreateTree(pUVM);
4395 }
4396 AssertReturn(pCtlInst, VERR_INTERNAL_ERROR);
4397
4398 if (enmBus == StorageBus_USB)
4399 {
4400 PCFGMNODE pCfg = NULL;
4401
4402 /* Create correct instance. */
4403 if (!fHotplug)
4404 {
4405 if (!fAttachDetach)
4406 InsertConfigNode(pCtlInst, Utf8StrFmt("%d", lPort).c_str(), &pCtlInst);
4407 else
4408 pCtlInst = CFGMR3GetChildF(pCtlInst, "%d/", lPort);
4409 }
4410
4411 if (!fAttachDetach)
4412 InsertConfigNode(pCtlInst, "Config", &pCfg);
4413
4414 uInstance = lPort; /* Overwrite uInstance with the correct one. */
4415
4416 if (!fHotplug && !fAttachDetach)
4417 {
4418 char aszUuid[RTUUID_STR_LENGTH + 1];
4419 USBStorageDevice UsbMsd = USBStorageDevice();
4420
4421 memset(aszUuid, 0, sizeof(aszUuid));
4422 rc = RTUuidCreate(&UsbMsd.mUuid);
4423 AssertRCReturn(rc, rc);
4424 rc = RTUuidToStr(&UsbMsd.mUuid, aszUuid, sizeof(aszUuid));
4425 AssertRCReturn(rc, rc);
4426
4427 UsbMsd.iPort = uInstance;
4428
4429 InsertConfigString(pCtlInst, "UUID", aszUuid);
4430 mUSBStorageDevices.push_back(UsbMsd);
4431
4432 /** @todo No LED after hotplugging. */
4433 /* Attach the status driver */
4434 Assert(cLedUsb >= 8);
4435 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedUsb], 0, 7,
4436 &mapMediumAttachments, pcszDevice, 0);
4437 paLedDevType = &maStorageDevType[iLedUsb];
4438 }
4439 }
4440
4441 rc = i_removeMediumDriverFromVm(pCtlInst, pcszDevice, uInstance, uLUN, enmBus, fAttachDetach,
4442 fHotplug, fForceUnmount, pUVM, lType, &pLunL0);
4443 if (RT_FAILURE(rc))
4444 return rc;
4445 if (ppLunL0)
4446 *ppLunL0 = pLunL0;
4447
4448 Utf8Str devicePath = Utf8StrFmt("%s/%u/LUN#%u", pcszDevice, uInstance, uLUN);
4449 mapMediumAttachments[devicePath] = pMediumAtt;
4450
4451 ComPtr<IMedium> pMedium;
4452 hrc = pMediumAtt->COMGETTER(Medium)(pMedium.asOutParam()); H();
4453
4454 /*
4455 * 1. Only check this for hard disk images.
4456 * 2. Only check during VM creation and not later, especially not during
4457 * taking an online snapshot!
4458 */
4459 if ( lType == DeviceType_HardDisk
4460 && ( aMachineState == MachineState_Starting
4461 || aMachineState == MachineState_Restoring))
4462 {
4463 rc = i_checkMediumLocation(pMedium, &fUseHostIOCache);
4464 if (RT_FAILURE(rc))
4465 return rc;
4466 }
4467
4468 BOOL fPassthrough = FALSE;
4469 if (pMedium)
4470 {
4471 BOOL fHostDrive;
4472 hrc = pMedium->COMGETTER(HostDrive)(&fHostDrive); H();
4473 if ( ( lType == DeviceType_DVD
4474 || lType == DeviceType_Floppy)
4475 && !fHostDrive)
4476 {
4477 /*
4478 * Informative logging.
4479 */
4480 Bstr strFile;
4481 hrc = pMedium->COMGETTER(Location)(strFile.asOutParam()); H();
4482 Utf8Str utfFile = Utf8Str(strFile);
4483 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
4484 (void)RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
4485 LogRel(("File system of '%s' (%s) is %s\n",
4486 utfFile.c_str(), lType == DeviceType_DVD ? "DVD" : "Floppy",
4487 RTFsTypeName(enmFsTypeFile)));
4488 }
4489
4490 if (fHostDrive)
4491 {
4492 hrc = pMediumAtt->COMGETTER(Passthrough)(&fPassthrough); H();
4493 }
4494 }
4495
4496 ComObjPtr<IBandwidthGroup> pBwGroup;
4497 Bstr strBwGroup;
4498 hrc = pMediumAtt->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
4499
4500 if (!pBwGroup.isNull())
4501 {
4502 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
4503 }
4504
4505 /*
4506 * Insert the SCSI driver for hotplug events on the SCSI/USB based storage controllers
4507 * or for SATA if the new device is a CD/DVD drive.
4508 */
4509 if ( (fHotplug || !fAttachDetach)
4510 && ( (enmBus == StorageBus_SCSI || enmBus == StorageBus_SAS || enmBus == StorageBus_USB || enmBus == StorageBus_VirtioSCSI)
4511 || (enmBus == StorageBus_SATA && lType == DeviceType_DVD && !fPassthrough)))
4512 {
4513 InsertConfigString(pLunL0, "Driver", "SCSI");
4514 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4515 }
4516
4517 rc = i_configMedium(pLunL0,
4518 !!fPassthrough,
4519 lType,
4520 fUseHostIOCache,
4521 fBuiltinIOCache,
4522 fInsertDiskIntegrityDrv,
4523 fSetupMerge,
4524 uMergeSource,
4525 uMergeTarget,
4526 strBwGroup.isEmpty() ? NULL : Utf8Str(strBwGroup).c_str(),
4527 !!fDiscard,
4528 !!fNonRotational,
4529 pMedium,
4530 aMachineState,
4531 phrc);
4532 if (RT_FAILURE(rc))
4533 return rc;
4534
4535 if (fAttachDetach)
4536 {
4537 /* Attach the new driver. */
4538 if (enmBus == StorageBus_USB)
4539 {
4540 if (fHotplug)
4541 {
4542 USBStorageDevice UsbMsd = USBStorageDevice();
4543 RTUuidCreate(&UsbMsd.mUuid);
4544 UsbMsd.iPort = uInstance;
4545 rc = PDMR3UsbCreateEmulatedDevice(pUVM, pcszDevice, pCtlInst, &UsbMsd.mUuid, NULL);
4546 if (RT_SUCCESS(rc))
4547 mUSBStorageDevices.push_back(UsbMsd);
4548 }
4549 else
4550 rc = PDMR3UsbDriverAttach(pUVM, pcszDevice, uInstance, uLUN,
4551 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4552 }
4553 else if ( !fHotplug
4554 && ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI || enmBus == StorageBus_VirtioSCSI)
4555 || (enmBus == StorageBus_SATA && lType == DeviceType_DVD)))
4556 rc = PDMR3DriverAttach(pUVM, pcszDevice, uInstance, uLUN,
4557 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4558 else
4559 rc = PDMR3DeviceAttach(pUVM, pcszDevice, uInstance, uLUN,
4560 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4561 AssertRCReturn(rc, rc);
4562
4563 /*
4564 * Make the secret key helper interface known to the VD driver if it is attached,
4565 * so we can get notified about missing keys.
4566 */
4567 PPDMIBASE pIBase = NULL;
4568 rc = PDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "VD", &pIBase);
4569 if (RT_SUCCESS(rc) && pIBase)
4570 {
4571 PPDMIMEDIA pIMedium = (PPDMIMEDIA)pIBase->pfnQueryInterface(pIBase, PDMIMEDIA_IID);
4572 if (pIMedium)
4573 {
4574 rc = pIMedium->pfnSetSecKeyIf(pIMedium, mpIfSecKey, mpIfSecKeyHlp);
4575 Assert(RT_SUCCESS(rc) || rc == VERR_NOT_SUPPORTED);
4576 }
4577 }
4578
4579 /* There is no need to handle removable medium mounting, as we
4580 * unconditionally replace everthing including the block driver level.
4581 * This means the new medium will be picked up automatically. */
4582 }
4583
4584 if (paLedDevType)
4585 paLedDevType[uLUN] = lType;
4586
4587 /* Dump the changed LUN if possible, dump the complete device otherwise */
4588 if ( aMachineState != MachineState_Starting
4589 && aMachineState != MachineState_Restoring)
4590 CFGMR3Dump(pLunL0 ? pLunL0 : pCtlInst);
4591 }
4592 catch (ConfigError &x)
4593 {
4594 // InsertConfig threw something:
4595 return x.m_vrc;
4596 }
4597
4598#undef H
4599
4600 return VINF_SUCCESS;
4601}
4602
4603int Console::i_configMedium(PCFGMNODE pLunL0,
4604 bool fPassthrough,
4605 DeviceType_T enmType,
4606 bool fUseHostIOCache,
4607 bool fBuiltinIOCache,
4608 bool fInsertDiskIntegrityDrv,
4609 bool fSetupMerge,
4610 unsigned uMergeSource,
4611 unsigned uMergeTarget,
4612 const char *pcszBwGroup,
4613 bool fDiscard,
4614 bool fNonRotational,
4615 IMedium *pMedium,
4616 MachineState_T aMachineState,
4617 HRESULT *phrc)
4618{
4619 // InsertConfig* throws
4620 try
4621 {
4622 HRESULT hrc;
4623 Bstr bstr;
4624 PCFGMNODE pCfg = NULL;
4625
4626#define H() \
4627 AssertMsgReturnStmt(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), if (phrc) *phrc = hrc, Global::vboxStatusCodeFromCOM(hrc))
4628
4629
4630 BOOL fHostDrive = FALSE;
4631 MediumType_T mediumType = MediumType_Normal;
4632 if (pMedium)
4633 {
4634 hrc = pMedium->COMGETTER(HostDrive)(&fHostDrive); H();
4635 hrc = pMedium->COMGETTER(Type)(&mediumType); H();
4636 }
4637
4638 if (fHostDrive)
4639 {
4640 Assert(pMedium);
4641 if (enmType == DeviceType_DVD)
4642 {
4643 InsertConfigString(pLunL0, "Driver", "HostDVD");
4644 InsertConfigNode(pLunL0, "Config", &pCfg);
4645
4646 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4647 InsertConfigString(pCfg, "Path", bstr);
4648
4649 InsertConfigInteger(pCfg, "Passthrough", fPassthrough);
4650 }
4651 else if (enmType == DeviceType_Floppy)
4652 {
4653 InsertConfigString(pLunL0, "Driver", "HostFloppy");
4654 InsertConfigNode(pLunL0, "Config", &pCfg);
4655
4656 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4657 InsertConfigString(pCfg, "Path", bstr);
4658 }
4659 }
4660 else
4661 {
4662 if (fInsertDiskIntegrityDrv)
4663 {
4664 /*
4665 * The actual configuration is done through CFGM extra data
4666 * for each inserted driver separately.
4667 */
4668 InsertConfigString(pLunL0, "Driver", "DiskIntegrity");
4669 InsertConfigNode(pLunL0, "Config", &pCfg);
4670 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4671 }
4672
4673 InsertConfigString(pLunL0, "Driver", "VD");
4674 InsertConfigNode(pLunL0, "Config", &pCfg);
4675 switch (enmType)
4676 {
4677 case DeviceType_DVD:
4678 InsertConfigString(pCfg, "Type", "DVD");
4679 InsertConfigInteger(pCfg, "Mountable", 1);
4680 break;
4681 case DeviceType_Floppy:
4682 InsertConfigString(pCfg, "Type", "Floppy 1.44");
4683 InsertConfigInteger(pCfg, "Mountable", 1);
4684 break;
4685 case DeviceType_HardDisk:
4686 default:
4687 InsertConfigString(pCfg, "Type", "HardDisk");
4688 InsertConfigInteger(pCfg, "Mountable", 0);
4689 }
4690
4691 if ( pMedium
4692 && ( enmType == DeviceType_DVD
4693 || enmType == DeviceType_Floppy)
4694 )
4695 {
4696 // if this medium represents an ISO image and this image is inaccessible,
4697 // the ignore it instead of causing a failure; this can happen when we
4698 // restore a VM state and the ISO has disappeared, e.g. because the Guest
4699 // Additions were mounted and the user upgraded VirtualBox. Previously
4700 // we failed on startup, but that's not good because the only way out then
4701 // would be to discard the VM state...
4702 MediumState_T mediumState;
4703 hrc = pMedium->RefreshState(&mediumState); H();
4704 if (mediumState == MediumState_Inaccessible)
4705 {
4706 Bstr loc;
4707 hrc = pMedium->COMGETTER(Location)(loc.asOutParam()); H();
4708 i_atVMRuntimeErrorCallbackF(0, "DvdOrFloppyImageInaccessible",
4709 "The image file '%ls' is inaccessible and is being ignored. "
4710 "Please select a different image file for the virtual %s drive.",
4711 loc.raw(),
4712 enmType == DeviceType_DVD ? "DVD" : "floppy");
4713 pMedium = NULL;
4714 }
4715 }
4716
4717 if (pMedium)
4718 {
4719 /* Start with length of parent chain, as the list is reversed */
4720 unsigned uImage = 0;
4721 IMedium *pTmp = pMedium;
4722 while (pTmp)
4723 {
4724 uImage++;
4725 hrc = pTmp->COMGETTER(Parent)(&pTmp); H();
4726 }
4727 /* Index of last image */
4728 uImage--;
4729
4730# ifdef VBOX_WITH_EXTPACK
4731 if (mptrExtPackManager->i_isExtPackUsable(ORACLE_PUEL_EXTPACK_NAME))
4732 {
4733 /* Configure loading the VDPlugin. */
4734 static const char s_szVDPlugin[] = "VDPluginCrypt";
4735 PCFGMNODE pCfgPlugins = NULL;
4736 PCFGMNODE pCfgPlugin = NULL;
4737 Utf8Str strPlugin;
4738 hrc = mptrExtPackManager->i_getLibraryPathForExtPack(s_szVDPlugin, ORACLE_PUEL_EXTPACK_NAME, &strPlugin);
4739 // Don't fail, this is optional!
4740 if (SUCCEEDED(hrc))
4741 {
4742 InsertConfigNode(pCfg, "Plugins", &pCfgPlugins);
4743 InsertConfigNode(pCfgPlugins, s_szVDPlugin, &pCfgPlugin);
4744 InsertConfigString(pCfgPlugin, "Path", strPlugin.c_str());
4745 }
4746 }
4747# endif
4748
4749 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4750 InsertConfigString(pCfg, "Path", bstr);
4751
4752 hrc = pMedium->COMGETTER(Format)(bstr.asOutParam()); H();
4753 InsertConfigString(pCfg, "Format", bstr);
4754
4755 if (mediumType == MediumType_Readonly)
4756 InsertConfigInteger(pCfg, "ReadOnly", 1);
4757 else if (enmType == DeviceType_Floppy)
4758 InsertConfigInteger(pCfg, "MaybeReadOnly", 1);
4759
4760 /* Start without exclusive write access to the images. */
4761 /** @todo Live Migration: I don't quite like this, we risk screwing up when
4762 * we're resuming the VM if some 3rd dude have any of the VDIs open
4763 * with write sharing denied. However, if the two VMs are sharing a
4764 * image it really is necessary....
4765 *
4766 * So, on the "lock-media" command, the target teleporter should also
4767 * make DrvVD undo TempReadOnly. It gets interesting if we fail after
4768 * that. Grumble. */
4769 if ( enmType == DeviceType_HardDisk
4770 && aMachineState == MachineState_TeleportingIn)
4771 InsertConfigInteger(pCfg, "TempReadOnly", 1);
4772
4773 /* Flag for opening the medium for sharing between VMs. This
4774 * is done at the moment only for the first (and only) medium
4775 * in the chain, as shared media can have no diffs. */
4776 if (mediumType == MediumType_Shareable)
4777 InsertConfigInteger(pCfg, "Shareable", 1);
4778
4779 if (!fUseHostIOCache)
4780 {
4781 InsertConfigInteger(pCfg, "UseNewIo", 1);
4782 /*
4783 * Activate the builtin I/O cache for harddisks only.
4784 * It caches writes only which doesn't make sense for DVD drives
4785 * and just increases the overhead.
4786 */
4787 if ( fBuiltinIOCache
4788 && (enmType == DeviceType_HardDisk))
4789 InsertConfigInteger(pCfg, "BlockCache", 1);
4790 }
4791
4792 if (fSetupMerge)
4793 {
4794 InsertConfigInteger(pCfg, "SetupMerge", 1);
4795 if (uImage == uMergeSource)
4796 InsertConfigInteger(pCfg, "MergeSource", 1);
4797 else if (uImage == uMergeTarget)
4798 InsertConfigInteger(pCfg, "MergeTarget", 1);
4799 }
4800
4801 if (pcszBwGroup)
4802 InsertConfigString(pCfg, "BwGroup", pcszBwGroup);
4803
4804 if (fDiscard)
4805 InsertConfigInteger(pCfg, "Discard", 1);
4806
4807 if (fNonRotational)
4808 InsertConfigInteger(pCfg, "NonRotationalMedium", 1);
4809
4810 /* Pass all custom parameters. */
4811 bool fHostIP = true;
4812 bool fEncrypted = false;
4813 hrc = i_configMediumProperties(pCfg, pMedium, &fHostIP, &fEncrypted); H();
4814
4815 /* Create an inverted list of parents. */
4816 uImage--;
4817 IMedium *pParentMedium = pMedium;
4818 for (PCFGMNODE pParent = pCfg;; uImage--)
4819 {
4820 hrc = pParentMedium->COMGETTER(Parent)(&pMedium); H();
4821 if (!pMedium)
4822 break;
4823
4824 PCFGMNODE pCur;
4825 InsertConfigNode(pParent, "Parent", &pCur);
4826 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4827 InsertConfigString(pCur, "Path", bstr);
4828
4829 hrc = pMedium->COMGETTER(Format)(bstr.asOutParam()); H();
4830 InsertConfigString(pCur, "Format", bstr);
4831
4832 if (fSetupMerge)
4833 {
4834 if (uImage == uMergeSource)
4835 InsertConfigInteger(pCur, "MergeSource", 1);
4836 else if (uImage == uMergeTarget)
4837 InsertConfigInteger(pCur, "MergeTarget", 1);
4838 }
4839
4840 /* Configure medium properties. */
4841 hrc = i_configMediumProperties(pCur, pMedium, &fHostIP, &fEncrypted); H();
4842
4843 /* next */
4844 pParent = pCur;
4845 pParentMedium = pMedium;
4846 }
4847
4848 /* Custom code: put marker to not use host IP stack to driver
4849 * configuration node. Simplifies life of DrvVD a bit. */
4850 if (!fHostIP)
4851 InsertConfigInteger(pCfg, "HostIPStack", 0);
4852
4853 if (fEncrypted)
4854 m_cDisksEncrypted++;
4855 }
4856 else
4857 {
4858 /* Set empty drive flag for DVD or floppy without media. */
4859 if ( enmType == DeviceType_DVD
4860 || enmType == DeviceType_Floppy)
4861 InsertConfigInteger(pCfg, "EmptyDrive", 1);
4862 }
4863 }
4864#undef H
4865 }
4866 catch (ConfigError &x)
4867 {
4868 // InsertConfig threw something:
4869 return x.m_vrc;
4870 }
4871
4872 return VINF_SUCCESS;
4873}
4874
4875/**
4876 * Adds the medium properties to the CFGM tree.
4877 *
4878 * @returns VBox status code.
4879 * @param pCur The current CFGM node.
4880 * @param pMedium The medium object to configure.
4881 * @param pfHostIP Where to return the value of the \"HostIPStack\" property if found.
4882 * @param pfEncrypted Where to return whether the medium is encrypted.
4883 */
4884int Console::i_configMediumProperties(PCFGMNODE pCur, IMedium *pMedium, bool *pfHostIP, bool *pfEncrypted)
4885{
4886 /* Pass all custom parameters. */
4887 SafeArray<BSTR> aNames;
4888 SafeArray<BSTR> aValues;
4889 HRESULT hrc = pMedium->GetProperties(NULL, ComSafeArrayAsOutParam(aNames),
4890 ComSafeArrayAsOutParam(aValues));
4891
4892 if ( SUCCEEDED(hrc)
4893 && aNames.size() != 0)
4894 {
4895 PCFGMNODE pVDC;
4896 InsertConfigNode(pCur, "VDConfig", &pVDC);
4897 for (size_t ii = 0; ii < aNames.size(); ++ii)
4898 {
4899 if (aValues[ii] && *aValues[ii])
4900 {
4901 Utf8Str name = aNames[ii];
4902 Utf8Str value = aValues[ii];
4903 size_t offSlash = name.find("/", 0);
4904 if ( offSlash != name.npos
4905 && !name.startsWith("Special/"))
4906 {
4907 com::Utf8Str strFilter;
4908 com::Utf8Str strKey;
4909
4910 hrc = strFilter.assignEx(name, 0, offSlash);
4911 if (FAILED(hrc))
4912 break;
4913
4914 hrc = strKey.assignEx(name, offSlash + 1, name.length() - offSlash - 1); /* Skip slash */
4915 if (FAILED(hrc))
4916 break;
4917
4918 PCFGMNODE pCfgFilterConfig = CFGMR3GetChild(pVDC, strFilter.c_str());
4919 if (!pCfgFilterConfig)
4920 InsertConfigNode(pVDC, strFilter.c_str(), &pCfgFilterConfig);
4921
4922 InsertConfigString(pCfgFilterConfig, strKey.c_str(), value);
4923 }
4924 else
4925 {
4926 InsertConfigString(pVDC, name.c_str(), value);
4927 if ( name.compare("HostIPStack") == 0
4928 && value.compare("0") == 0)
4929 *pfHostIP = false;
4930 }
4931
4932 if ( name.compare("CRYPT/KeyId") == 0
4933 && pfEncrypted)
4934 *pfEncrypted = true;
4935 }
4936 }
4937 }
4938
4939 return hrc;
4940}
4941
4942
4943/**
4944 * Construct the Network configuration tree
4945 *
4946 * @returns VBox status code.
4947 *
4948 * @param pszDevice The PDM device name.
4949 * @param uInstance The PDM device instance.
4950 * @param uLun The PDM LUN number of the drive.
4951 * @param aNetworkAdapter The network adapter whose attachment needs to be changed
4952 * @param pCfg Configuration node for the device
4953 * @param pLunL0 To store the pointer to the LUN#0.
4954 * @param pInst The instance CFGM node
4955 * @param fAttachDetach To determine if the network attachment should
4956 * be attached/detached after/before
4957 * configuration.
4958 * @param fIgnoreConnectFailure
4959 * True if connection failures should be ignored
4960 * (makes only sense for bridged/host-only networks).
4961 *
4962 * @note Locks this object for writing.
4963 * @thread EMT
4964 */
4965int Console::i_configNetwork(const char *pszDevice,
4966 unsigned uInstance,
4967 unsigned uLun,
4968 INetworkAdapter *aNetworkAdapter,
4969 PCFGMNODE pCfg,
4970 PCFGMNODE pLunL0,
4971 PCFGMNODE pInst,
4972 bool fAttachDetach,
4973 bool fIgnoreConnectFailure)
4974{
4975 RT_NOREF(fIgnoreConnectFailure);
4976 AutoCaller autoCaller(this);
4977 AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED);
4978
4979 // InsertConfig* throws
4980 try
4981 {
4982 int rc = VINF_SUCCESS;
4983 HRESULT hrc;
4984 Bstr bstr;
4985
4986#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4987
4988 /*
4989 * Locking the object before doing VMR3* calls is quite safe here, since
4990 * we're on EMT. Write lock is necessary because we indirectly modify the
4991 * meAttachmentType member.
4992 */
4993 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
4994
4995 ComPtr<IMachine> pMachine = i_machine();
4996
4997 ComPtr<IVirtualBox> virtualBox;
4998 hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam()); H();
4999
5000 ComPtr<IHost> host;
5001 hrc = virtualBox->COMGETTER(Host)(host.asOutParam()); H();
5002
5003 BOOL fSniffer;
5004 hrc = aNetworkAdapter->COMGETTER(TraceEnabled)(&fSniffer); H();
5005
5006 NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy;
5007 hrc = aNetworkAdapter->COMGETTER(PromiscModePolicy)(&enmPromiscModePolicy); H();
5008 const char *pszPromiscuousGuestPolicy;
5009 switch (enmPromiscModePolicy)
5010 {
5011 case NetworkAdapterPromiscModePolicy_Deny: pszPromiscuousGuestPolicy = "deny"; break;
5012 case NetworkAdapterPromiscModePolicy_AllowNetwork: pszPromiscuousGuestPolicy = "allow-network"; break;
5013 case NetworkAdapterPromiscModePolicy_AllowAll: pszPromiscuousGuestPolicy = "allow-all"; break;
5014 default: AssertFailedReturn(VERR_INTERNAL_ERROR_4);
5015 }
5016
5017 if (fAttachDetach)
5018 {
5019 rc = PDMR3DeviceDetach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/);
5020 if (rc == VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN)
5021 rc = VINF_SUCCESS;
5022 AssertLogRelRCReturn(rc, rc);
5023
5024 /* Nuke anything which might have been left behind. */
5025 CFGMR3RemoveNode(CFGMR3GetChildF(pInst, "LUN#%u", uLun));
5026 }
5027
5028#ifdef VBOX_WITH_NETSHAPER
5029 ComObjPtr<IBandwidthGroup> pBwGroup;
5030 Bstr strBwGroup;
5031 hrc = aNetworkAdapter->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
5032
5033 if (!pBwGroup.isNull())
5034 {
5035 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
5036 }
5037#endif /* VBOX_WITH_NETSHAPER */
5038
5039 AssertMsg(uLun == 0, ("Network attachments with LUN > 0 are not supported yet\n"));
5040 CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%u", uLun);
5041
5042#ifdef VBOX_WITH_NETSHAPER
5043 if (!strBwGroup.isEmpty())
5044 {
5045 InsertConfigString(pLunL0, "Driver", "NetShaper");
5046 InsertConfigNode(pLunL0, "Config", &pCfg);
5047 InsertConfigString(pCfg, "BwGroup", strBwGroup);
5048 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
5049 }
5050#endif /* VBOX_WITH_NETSHAPER */
5051
5052 if (fSniffer)
5053 {
5054 InsertConfigString(pLunL0, "Driver", "NetSniffer");
5055 InsertConfigNode(pLunL0, "Config", &pCfg);
5056 hrc = aNetworkAdapter->COMGETTER(TraceFile)(bstr.asOutParam()); H();
5057 if (!bstr.isEmpty()) /* check convention for indicating default file. */
5058 InsertConfigString(pCfg, "File", bstr);
5059 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
5060 }
5061
5062
5063 Bstr networkName, trunkName, trunkType;
5064 NetworkAttachmentType_T eAttachmentType;
5065 hrc = aNetworkAdapter->COMGETTER(AttachmentType)(&eAttachmentType); H();
5066 switch (eAttachmentType)
5067 {
5068 case NetworkAttachmentType_Null:
5069 break;
5070
5071 case NetworkAttachmentType_NAT:
5072 {
5073 ComPtr<INATEngine> natEngine;
5074 hrc = aNetworkAdapter->COMGETTER(NATEngine)(natEngine.asOutParam()); H();
5075 InsertConfigString(pLunL0, "Driver", "NAT");
5076 InsertConfigNode(pLunL0, "Config", &pCfg);
5077
5078 /* Configure TFTP prefix and boot filename. */
5079 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
5080 if (!bstr.isEmpty())
5081 InsertConfigString(pCfg, "TFTPPrefix", Utf8StrFmt("%ls%c%s", bstr.raw(), RTPATH_DELIMITER, "TFTP"));
5082 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
5083 InsertConfigString(pCfg, "BootFile", Utf8StrFmt("%ls.pxe", bstr.raw()));
5084
5085 hrc = natEngine->COMGETTER(Network)(bstr.asOutParam()); H();
5086 if (!bstr.isEmpty())
5087 InsertConfigString(pCfg, "Network", bstr);
5088 else
5089 {
5090 ULONG uSlot;
5091 hrc = aNetworkAdapter->COMGETTER(Slot)(&uSlot); H();
5092 InsertConfigString(pCfg, "Network", Utf8StrFmt("10.0.%d.0/24", uSlot+2));
5093 }
5094 hrc = natEngine->COMGETTER(HostIP)(bstr.asOutParam()); H();
5095 if (!bstr.isEmpty())
5096 InsertConfigString(pCfg, "BindIP", bstr);
5097 ULONG mtu = 0;
5098 ULONG sockSnd = 0;
5099 ULONG sockRcv = 0;
5100 ULONG tcpSnd = 0;
5101 ULONG tcpRcv = 0;
5102 hrc = natEngine->GetNetworkSettings(&mtu, &sockSnd, &sockRcv, &tcpSnd, &tcpRcv); H();
5103 if (mtu)
5104 InsertConfigInteger(pCfg, "SlirpMTU", mtu);
5105 if (sockRcv)
5106 InsertConfigInteger(pCfg, "SockRcv", sockRcv);
5107 if (sockSnd)
5108 InsertConfigInteger(pCfg, "SockSnd", sockSnd);
5109 if (tcpRcv)
5110 InsertConfigInteger(pCfg, "TcpRcv", tcpRcv);
5111 if (tcpSnd)
5112 InsertConfigInteger(pCfg, "TcpSnd", tcpSnd);
5113 hrc = natEngine->COMGETTER(TFTPPrefix)(bstr.asOutParam()); H();
5114 if (!bstr.isEmpty())
5115 {
5116 RemoveConfigValue(pCfg, "TFTPPrefix");
5117 InsertConfigString(pCfg, "TFTPPrefix", bstr);
5118 }
5119 hrc = natEngine->COMGETTER(TFTPBootFile)(bstr.asOutParam()); H();
5120 if (!bstr.isEmpty())
5121 {
5122 RemoveConfigValue(pCfg, "BootFile");
5123 InsertConfigString(pCfg, "BootFile", bstr);
5124 }
5125 hrc = natEngine->COMGETTER(TFTPNextServer)(bstr.asOutParam()); H();
5126 if (!bstr.isEmpty())
5127 InsertConfigString(pCfg, "NextServer", bstr);
5128 BOOL fDNSFlag;
5129 hrc = natEngine->COMGETTER(DNSPassDomain)(&fDNSFlag); H();
5130 InsertConfigInteger(pCfg, "PassDomain", fDNSFlag);
5131 hrc = natEngine->COMGETTER(DNSProxy)(&fDNSFlag); H();
5132 InsertConfigInteger(pCfg, "DNSProxy", fDNSFlag);
5133 hrc = natEngine->COMGETTER(DNSUseHostResolver)(&fDNSFlag); H();
5134 InsertConfigInteger(pCfg, "UseHostResolver", fDNSFlag);
5135
5136 ULONG aliasMode;
5137 hrc = natEngine->COMGETTER(AliasMode)(&aliasMode); H();
5138 InsertConfigInteger(pCfg, "AliasMode", aliasMode);
5139
5140 /* port-forwarding */
5141 SafeArray<BSTR> pfs;
5142 hrc = natEngine->COMGETTER(Redirects)(ComSafeArrayAsOutParam(pfs)); H();
5143
5144 PCFGMNODE pPFTree = NULL;
5145 if (pfs.size() > 0)
5146 InsertConfigNode(pCfg, "PortForwarding", &pPFTree);
5147
5148 for (unsigned int i = 0; i < pfs.size(); ++i)
5149 {
5150 PCFGMNODE pPF = NULL; /* /Devices/Dev/.../Config/PortForwarding/$n/ */
5151
5152 uint16_t port = 0;
5153 Utf8Str utf = pfs[i];
5154 Utf8Str strName;
5155 Utf8Str strProto;
5156 Utf8Str strHostPort;
5157 Utf8Str strHostIP;
5158 Utf8Str strGuestPort;
5159 Utf8Str strGuestIP;
5160 size_t pos, ppos;
5161 pos = ppos = 0;
5162#define ITERATE_TO_NEXT_TERM(res, str, pos, ppos) \
5163 { \
5164 pos = str.find(",", ppos); \
5165 if (pos == Utf8Str::npos) \
5166 { \
5167 Log(( #res " extracting from %s is failed\n", str.c_str())); \
5168 continue; \
5169 } \
5170 res = str.substr(ppos, pos - ppos); \
5171 Log2((#res " %s pos:%d, ppos:%d\n", res.c_str(), pos, ppos)); \
5172 ppos = pos + 1; \
5173 } /* no do { ... } while because of 'continue' */
5174 ITERATE_TO_NEXT_TERM(strName, utf, pos, ppos);
5175 ITERATE_TO_NEXT_TERM(strProto, utf, pos, ppos);
5176 ITERATE_TO_NEXT_TERM(strHostIP, utf, pos, ppos);
5177 ITERATE_TO_NEXT_TERM(strHostPort, utf, pos, ppos);
5178 ITERATE_TO_NEXT_TERM(strGuestIP, utf, pos, ppos);
5179 strGuestPort = utf.substr(ppos, utf.length() - ppos);
5180#undef ITERATE_TO_NEXT_TERM
5181
5182 uint32_t proto = strProto.toUInt32();
5183 bool fValid = true;
5184 switch (proto)
5185 {
5186 case NATProtocol_UDP:
5187 strProto = "UDP";
5188 break;
5189 case NATProtocol_TCP:
5190 strProto = "TCP";
5191 break;
5192 default:
5193 fValid = false;
5194 }
5195 /* continue with next rule if no valid proto was passed */
5196 if (!fValid)
5197 continue;
5198
5199 InsertConfigNode(pPFTree, Utf8StrFmt("%u", i).c_str(), &pPF);
5200
5201 if (!strName.isEmpty())
5202 InsertConfigString(pPF, "Name", strName);
5203
5204 InsertConfigString(pPF, "Protocol", strProto);
5205
5206 if (!strHostIP.isEmpty())
5207 InsertConfigString(pPF, "BindIP", strHostIP);
5208
5209 if (!strGuestIP.isEmpty())
5210 InsertConfigString(pPF, "GuestIP", strGuestIP);
5211
5212 port = RTStrToUInt16(strHostPort.c_str());
5213 if (port)
5214 InsertConfigInteger(pPF, "HostPort", port);
5215
5216 port = RTStrToUInt16(strGuestPort.c_str());
5217 if (port)
5218 InsertConfigInteger(pPF, "GuestPort", port);
5219 }
5220 break;
5221 }
5222
5223 case NetworkAttachmentType_Bridged:
5224 {
5225#if (defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)) && !defined(VBOX_WITH_NETFLT)
5226 hrc = i_attachToTapInterface(aNetworkAdapter);
5227 if (FAILED(hrc))
5228 {
5229 switch (hrc)
5230 {
5231 case VERR_ACCESS_DENIED:
5232 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5233 "Failed to open '/dev/net/tun' for read/write access. Please check the "
5234 "permissions of that node. Either run 'chmod 0666 /dev/net/tun' or "
5235 "change the group of that node and make yourself a member of that group. Make "
5236 "sure that these changes are permanent, especially if you are "
5237 "using udev"));
5238 default:
5239 AssertMsgFailed(("Could not attach to host interface! Bad!\n"));
5240 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5241 "Failed to initialize Host Interface Networking"));
5242 }
5243 }
5244
5245 Assert((intptr_t)maTapFD[uInstance] >= 0);
5246 if ((intptr_t)maTapFD[uInstance] >= 0)
5247 {
5248 InsertConfigString(pLunL0, "Driver", "HostInterface");
5249 InsertConfigNode(pLunL0, "Config", &pCfg);
5250 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
5251 }
5252
5253#elif defined(VBOX_WITH_NETFLT)
5254 /*
5255 * This is the new VBoxNetFlt+IntNet stuff.
5256 */
5257 Bstr BridgedIfName;
5258 hrc = aNetworkAdapter->COMGETTER(BridgedInterface)(BridgedIfName.asOutParam());
5259 if (FAILED(hrc))
5260 {
5261 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(BridgedInterface) failed, hrc (0x%x)\n", hrc));
5262 H();
5263 }
5264
5265 Utf8Str BridgedIfNameUtf8(BridgedIfName);
5266 const char *pszBridgedIfName = BridgedIfNameUtf8.c_str();
5267
5268 ComPtr<IHostNetworkInterface> hostInterface;
5269 hrc = host->FindHostNetworkInterfaceByName(BridgedIfName.raw(),
5270 hostInterface.asOutParam());
5271 if (!SUCCEEDED(hrc))
5272 {
5273 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: FindByName failed, rc=%Rhrc (0x%x)", hrc, hrc));
5274 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5275 N_("Nonexistent host networking interface, name '%ls'"),
5276 BridgedIfName.raw());
5277 }
5278
5279# if defined(RT_OS_DARWIN)
5280 /* The name is on the form 'ifX: long name', chop it off at the colon. */
5281 char szTrunk[INTNET_MAX_TRUNK_NAME];
5282 RTStrCopy(szTrunk, sizeof(szTrunk), pszBridgedIfName);
5283 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
5284// Quick fix for @bugref{5633}
5285// if (!pszColon)
5286// {
5287// /*
5288// * Dynamic changing of attachment causes an attempt to configure
5289// * network with invalid host adapter (as it is must be changed before
5290// * the attachment), calling Detach here will cause a deadlock.
5291// * See @bugref{4750}.
5292// * hrc = aNetworkAdapter->Detach(); H();
5293// */
5294// return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5295// N_("Malformed host interface networking name '%ls'"),
5296// BridgedIfName.raw());
5297// }
5298 if (pszColon)
5299 *pszColon = '\0';
5300 const char *pszTrunk = szTrunk;
5301
5302# elif defined(RT_OS_SOLARIS)
5303 /* The name is on the form format 'ifX[:1] - long name, chop it off at space. */
5304 char szTrunk[256];
5305 strlcpy(szTrunk, pszBridgedIfName, sizeof(szTrunk));
5306 char *pszSpace = (char *)memchr(szTrunk, ' ', sizeof(szTrunk));
5307
5308 /*
5309 * Currently don't bother about malformed names here for the sake of people using
5310 * VBoxManage and setting only the NIC name from there. If there is a space we
5311 * chop it off and proceed, otherwise just use whatever we've got.
5312 */
5313 if (pszSpace)
5314 *pszSpace = '\0';
5315
5316 /* Chop it off at the colon (zone naming eg: e1000g:1 we need only the e1000g) */
5317 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
5318 if (pszColon)
5319 *pszColon = '\0';
5320
5321 const char *pszTrunk = szTrunk;
5322
5323# elif defined(RT_OS_WINDOWS)
5324 HostNetworkInterfaceType_T eIfType;
5325 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
5326 if (FAILED(hrc))
5327 {
5328 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
5329 H();
5330 }
5331
5332 if (eIfType != HostNetworkInterfaceType_Bridged)
5333 {
5334 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5335 N_("Interface ('%ls') is not a Bridged Adapter interface"),
5336 BridgedIfName.raw());
5337 }
5338
5339 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
5340 if (FAILED(hrc))
5341 {
5342 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
5343 H();
5344 }
5345 Guid hostIFGuid(bstr);
5346
5347 INetCfg *pNc;
5348 ComPtr<INetCfgComponent> pAdaptorComponent;
5349 LPWSTR pszApp;
5350
5351 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
5352 Assert(hrc == S_OK);
5353 if (hrc != S_OK)
5354 {
5355 LogRel(("NetworkAttachmentType_Bridged: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5356 H();
5357 }
5358
5359 /* get the adapter's INetCfgComponent*/
5360 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
5361 pAdaptorComponent.asOutParam());
5362 if (hrc != S_OK)
5363 {
5364 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5365 LogRel(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)\n", hrc));
5366 H();
5367 }
5368# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
5369 char szTrunkName[INTNET_MAX_TRUNK_NAME];
5370 char *pszTrunkName = szTrunkName;
5371 wchar_t * pswzBindName;
5372 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
5373 Assert(hrc == S_OK);
5374 if (hrc == S_OK)
5375 {
5376 int cwBindName = (int)wcslen(pswzBindName) + 1;
5377 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
5378 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
5379 {
5380 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
5381 pszTrunkName += cbFullBindNamePrefix-1;
5382 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
5383 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
5384 {
5385 DWORD err = GetLastError();
5386 hrc = HRESULT_FROM_WIN32(err);
5387 AssertMsgFailed(("hrc=%Rhrc %#x\n", hrc, hrc));
5388 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
5389 hrc, hrc, err));
5390 }
5391 }
5392 else
5393 {
5394 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: insufficient szTrunkName buffer space\n"));
5395 /** @todo set appropriate error code */
5396 hrc = E_FAIL;
5397 }
5398
5399 if (hrc != S_OK)
5400 {
5401 AssertFailed();
5402 CoTaskMemFree(pswzBindName);
5403 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5404 H();
5405 }
5406
5407 /* we're not freeing the bind name since we'll use it later for detecting wireless*/
5408 }
5409 else
5410 {
5411 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5412 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)",
5413 hrc));
5414 H();
5415 }
5416
5417 const char *pszTrunk = szTrunkName;
5418 /* we're not releasing the INetCfg stuff here since we use it later to figure out whether it is wireless */
5419
5420# elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
5421# if defined(RT_OS_FREEBSD)
5422 /*
5423 * If we bridge to a tap interface open it the `old' direct way.
5424 * This works and performs better than bridging a physical
5425 * interface via the current FreeBSD vboxnetflt implementation.
5426 */
5427 if (!strncmp(pszBridgedIfName, RT_STR_TUPLE("tap"))) {
5428 hrc = i_attachToTapInterface(aNetworkAdapter);
5429 if (FAILED(hrc))
5430 {
5431 switch (hrc)
5432 {
5433 case E_ACCESSDENIED:
5434 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5435 "Failed to open '/dev/%s' for read/write access. Please check the "
5436 "permissions of that node, and that the net.link.tap.user_open "
5437 "sysctl is set. Either run 'chmod 0666 /dev/%s' or "
5438 "change the group of that node to vboxusers and make yourself "
5439 "a member of that group. Make sure that these changes are permanent."),
5440 pszBridgedIfName, pszBridgedIfName);
5441 default:
5442 AssertMsgFailed(("Could not attach to tap interface! Bad!\n"));
5443 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5444 "Failed to initialize Host Interface Networking"));
5445 }
5446 }
5447
5448 Assert((intptr_t)maTapFD[uInstance] >= 0);
5449 if ((intptr_t)maTapFD[uInstance] >= 0)
5450 {
5451 InsertConfigString(pLunL0, "Driver", "HostInterface");
5452 InsertConfigNode(pLunL0, "Config", &pCfg);
5453 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
5454 }
5455 break;
5456 }
5457# endif
5458 /** @todo Check for malformed names. */
5459 const char *pszTrunk = pszBridgedIfName;
5460
5461 /* Issue a warning if the interface is down */
5462 {
5463 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
5464 if (iSock >= 0)
5465 {
5466 struct ifreq Req;
5467 RT_ZERO(Req);
5468 RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pszBridgedIfName);
5469 if (ioctl(iSock, SIOCGIFFLAGS, &Req) >= 0)
5470 if ((Req.ifr_flags & IFF_UP) == 0)
5471 i_atVMRuntimeErrorCallbackF(0, "BridgedInterfaceDown",
5472 N_("Bridged interface %s is down. Guest will not be able to use this interface"),
5473 pszBridgedIfName);
5474
5475 close(iSock);
5476 }
5477 }
5478
5479# else
5480# error "PORTME (VBOX_WITH_NETFLT)"
5481# endif
5482
5483 InsertConfigString(pLunL0, "Driver", "IntNet");
5484 InsertConfigNode(pLunL0, "Config", &pCfg);
5485 InsertConfigString(pCfg, "Trunk", pszTrunk);
5486 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
5487 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure);
5488 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5489 char szNetwork[INTNET_MAX_NETWORK_NAME];
5490
5491# if defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN)
5492 /*
5493 * 'pszTrunk' contains just the interface name required in ring-0, while 'pszBridgedIfName' contains
5494 * interface name + optional description. We must not pass any description to the VM as it can differ
5495 * for the same interface name, eg: "nge0 - ethernet" (GUI) vs "nge0" (VBoxManage).
5496 */
5497 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszTrunk);
5498# else
5499 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszBridgedIfName);
5500# endif
5501 InsertConfigString(pCfg, "Network", szNetwork);
5502 networkName = Bstr(szNetwork);
5503 trunkName = Bstr(pszTrunk);
5504 trunkType = Bstr(TRUNKTYPE_NETFLT);
5505
5506 BOOL fSharedMacOnWire = false;
5507 hrc = hostInterface->COMGETTER(Wireless)(&fSharedMacOnWire);
5508 if (FAILED(hrc))
5509 {
5510 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Wireless) failed, hrc (0x%x)\n", hrc));
5511 H();
5512 }
5513 else if (fSharedMacOnWire)
5514 {
5515 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5516 Log(("Set SharedMacOnWire\n"));
5517 }
5518
5519# if defined(RT_OS_SOLARIS)
5520# if 0 /* bird: this is a bit questionable and might cause more trouble than its worth. */
5521 /* Zone access restriction, don't allow snooping the global zone. */
5522 zoneid_t ZoneId = getzoneid();
5523 if (ZoneId != GLOBAL_ZONEID)
5524 {
5525 InsertConfigInteger(pCfg, "IgnoreAllPromisc", true);
5526 }
5527# endif
5528# endif
5529
5530#elif defined(RT_OS_WINDOWS) /* not defined NetFlt */
5531 /* NOTHING TO DO HERE */
5532#elif defined(RT_OS_LINUX)
5533/// @todo aleksey: is there anything to be done here?
5534#elif defined(RT_OS_FREEBSD)
5535/** @todo FreeBSD: Check out this later (HIF networking). */
5536#else
5537# error "Port me"
5538#endif
5539 break;
5540 }
5541
5542 case NetworkAttachmentType_Internal:
5543 {
5544 hrc = aNetworkAdapter->COMGETTER(InternalNetwork)(bstr.asOutParam()); H();
5545 if (!bstr.isEmpty())
5546 {
5547 InsertConfigString(pLunL0, "Driver", "IntNet");
5548 InsertConfigNode(pLunL0, "Config", &pCfg);
5549 InsertConfigString(pCfg, "Network", bstr);
5550 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
5551 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5552 networkName = bstr;
5553 trunkType = Bstr(TRUNKTYPE_WHATEVER);
5554 }
5555 break;
5556 }
5557
5558 case NetworkAttachmentType_HostOnly:
5559 {
5560 InsertConfigString(pLunL0, "Driver", "IntNet");
5561 InsertConfigNode(pLunL0, "Config", &pCfg);
5562
5563 Bstr HostOnlyName;
5564 hrc = aNetworkAdapter->COMGETTER(HostOnlyInterface)(HostOnlyName.asOutParam());
5565 if (FAILED(hrc))
5566 {
5567 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(HostOnlyInterface) failed, hrc (0x%x)\n", hrc));
5568 H();
5569 }
5570
5571 Utf8Str HostOnlyNameUtf8(HostOnlyName);
5572 const char *pszHostOnlyName = HostOnlyNameUtf8.c_str();
5573 ComPtr<IHostNetworkInterface> hostInterface;
5574 rc = host->FindHostNetworkInterfaceByName(HostOnlyName.raw(),
5575 hostInterface.asOutParam());
5576 if (!SUCCEEDED(rc))
5577 {
5578 LogRel(("NetworkAttachmentType_HostOnly: FindByName failed, rc (0x%x)\n", rc));
5579 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5580 N_("Nonexistent host networking interface, name '%ls'"),
5581 HostOnlyName.raw());
5582 }
5583
5584 char szNetwork[INTNET_MAX_NETWORK_NAME];
5585 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszHostOnlyName);
5586
5587#if defined(RT_OS_WINDOWS)
5588# ifndef VBOX_WITH_NETFLT
5589 hrc = E_NOTIMPL;
5590 LogRel(("NetworkAttachmentType_HostOnly: Not Implemented\n"));
5591 H();
5592# else /* defined VBOX_WITH_NETFLT*/
5593 /** @todo r=bird: Put this in a function. */
5594
5595 HostNetworkInterfaceType_T eIfType;
5596 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
5597 if (FAILED(hrc))
5598 {
5599 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
5600 H();
5601 }
5602
5603 if (eIfType != HostNetworkInterfaceType_HostOnly)
5604 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5605 N_("Interface ('%ls') is not a Host-Only Adapter interface"),
5606 HostOnlyName.raw());
5607
5608 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
5609 if (FAILED(hrc))
5610 {
5611 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
5612 H();
5613 }
5614 Guid hostIFGuid(bstr);
5615
5616 INetCfg *pNc;
5617 ComPtr<INetCfgComponent> pAdaptorComponent;
5618 LPWSTR pszApp;
5619 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
5620 Assert(hrc == S_OK);
5621 if (hrc != S_OK)
5622 {
5623 LogRel(("NetworkAttachmentType_HostOnly: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5624 H();
5625 }
5626
5627 /* get the adapter's INetCfgComponent*/
5628 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
5629 pAdaptorComponent.asOutParam());
5630 if (hrc != S_OK)
5631 {
5632 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5633 LogRel(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5634 H();
5635 }
5636# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
5637 char szTrunkName[INTNET_MAX_TRUNK_NAME];
5638 bool fNdis6 = false;
5639 wchar_t * pwszHelpText;
5640 hrc = pAdaptorComponent->GetHelpText(&pwszHelpText);
5641 Assert(hrc == S_OK);
5642 if (hrc == S_OK)
5643 {
5644 Log(("help-text=%ls\n", pwszHelpText));
5645 if (!wcscmp(pwszHelpText, L"VirtualBox NDIS 6.0 Miniport Driver"))
5646 fNdis6 = true;
5647 CoTaskMemFree(pwszHelpText);
5648 }
5649 if (fNdis6)
5650 {
5651 strncpy(szTrunkName, pszHostOnlyName, sizeof(szTrunkName) - 1);
5652 Log(("trunk=%s\n", szTrunkName));
5653 }
5654 else
5655 {
5656 char *pszTrunkName = szTrunkName;
5657 wchar_t * pswzBindName;
5658 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
5659 Assert(hrc == S_OK);
5660 if (hrc == S_OK)
5661 {
5662 int cwBindName = (int)wcslen(pswzBindName) + 1;
5663 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
5664 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
5665 {
5666 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
5667 pszTrunkName += cbFullBindNamePrefix-1;
5668 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
5669 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
5670 {
5671 DWORD err = GetLastError();
5672 hrc = HRESULT_FROM_WIN32(err);
5673 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
5674 hrc, hrc, err));
5675 }
5676 }
5677 else
5678 {
5679 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: insufficient szTrunkName buffer space\n"));
5680 /** @todo set appropriate error code */
5681 hrc = E_FAIL;
5682 }
5683
5684 if (hrc != S_OK)
5685 {
5686 AssertFailed();
5687 CoTaskMemFree(pswzBindName);
5688 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5689 H();
5690 }
5691 }
5692 else
5693 {
5694 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5695 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n",
5696 hrc, hrc));
5697 H();
5698 }
5699
5700
5701 CoTaskMemFree(pswzBindName);
5702 }
5703
5704 trunkType = TRUNKTYPE_NETADP;
5705 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
5706
5707 pAdaptorComponent.setNull();
5708 /* release the pNc finally */
5709 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5710
5711 const char *pszTrunk = szTrunkName;
5712
5713 InsertConfigString(pCfg, "Trunk", pszTrunk);
5714 InsertConfigString(pCfg, "Network", szNetwork);
5715 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure); /** @todo why is this
5716 windows only?? */
5717 networkName = Bstr(szNetwork);
5718 trunkName = Bstr(pszTrunk);
5719# endif /* defined VBOX_WITH_NETFLT*/
5720#elif defined(RT_OS_DARWIN)
5721 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
5722 InsertConfigString(pCfg, "Network", szNetwork);
5723 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
5724 networkName = Bstr(szNetwork);
5725 trunkName = Bstr(pszHostOnlyName);
5726 trunkType = TRUNKTYPE_NETADP;
5727#else
5728 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
5729 InsertConfigString(pCfg, "Network", szNetwork);
5730 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
5731 networkName = Bstr(szNetwork);
5732 trunkName = Bstr(pszHostOnlyName);
5733 trunkType = TRUNKTYPE_NETFLT;
5734#endif
5735 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5736
5737#if !defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
5738
5739 Bstr tmpAddr, tmpMask;
5740
5741 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPAddress",
5742 pszHostOnlyName).raw(),
5743 tmpAddr.asOutParam());
5744 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty())
5745 {
5746 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPNetMask",
5747 pszHostOnlyName).raw(),
5748 tmpMask.asOutParam());
5749 if (SUCCEEDED(hrc) && !tmpMask.isEmpty())
5750 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
5751 tmpMask.raw());
5752 else
5753 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
5754 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
5755 }
5756 else
5757 {
5758 /* Grab the IP number from the 'vboxnetX' instance number (see netif.h) */
5759 hrc = hostInterface->EnableStaticIPConfig(getDefaultIPv4Address(Bstr(pszHostOnlyName)).raw(),
5760 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
5761 }
5762
5763 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
5764
5765 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6Address",
5766 pszHostOnlyName).raw(),
5767 tmpAddr.asOutParam());
5768 if (SUCCEEDED(hrc))
5769 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6NetMask", pszHostOnlyName).raw(),
5770 tmpMask.asOutParam());
5771 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty() && !tmpMask.isEmpty())
5772 {
5773 hrc = hostInterface->EnableStaticIPConfigV6(tmpAddr.raw(),
5774 Utf8Str(tmpMask).toUInt32());
5775 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
5776 }
5777#endif
5778 break;
5779 }
5780
5781 case NetworkAttachmentType_Generic:
5782 {
5783 hrc = aNetworkAdapter->COMGETTER(GenericDriver)(bstr.asOutParam()); H();
5784 SafeArray<BSTR> names;
5785 SafeArray<BSTR> values;
5786 hrc = aNetworkAdapter->GetProperties(Bstr().raw(),
5787 ComSafeArrayAsOutParam(names),
5788 ComSafeArrayAsOutParam(values)); H();
5789
5790 InsertConfigString(pLunL0, "Driver", bstr);
5791 InsertConfigNode(pLunL0, "Config", &pCfg);
5792 for (size_t ii = 0; ii < names.size(); ++ii)
5793 {
5794 if (values[ii] && *values[ii])
5795 {
5796 Utf8Str name = names[ii];
5797 Utf8Str value = values[ii];
5798 InsertConfigString(pCfg, name.c_str(), value);
5799 }
5800 }
5801 break;
5802 }
5803
5804 case NetworkAttachmentType_NATNetwork:
5805 {
5806 hrc = aNetworkAdapter->COMGETTER(NATNetwork)(bstr.asOutParam()); H();
5807 if (!bstr.isEmpty())
5808 {
5809 /** @todo add intnet prefix to separate namespaces, and add trunk if dealing with vboxnatX */
5810 InsertConfigString(pLunL0, "Driver", "IntNet");
5811 InsertConfigNode(pLunL0, "Config", &pCfg);
5812 InsertConfigString(pCfg, "Network", bstr);
5813 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
5814 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5815 networkName = bstr;
5816 trunkType = Bstr(TRUNKTYPE_WHATEVER);
5817 }
5818 break;
5819 }
5820
5821#ifdef VBOX_WITH_CLOUD_NET
5822 case NetworkAttachmentType_Cloud:
5823 {
5824 hrc = aNetworkAdapter->COMGETTER(CloudNetwork)(bstr.asOutParam()); H();
5825 if (!bstr.isEmpty())
5826 {
5827 InsertConfigString(pLunL0, "Driver", "IntNet");
5828 InsertConfigNode(pLunL0, "Config", &pCfg);
5829 InsertConfigString(pCfg, "Network", BstrFmt("cloud-%ls", bstr));
5830 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
5831 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5832 networkName = bstr;
5833 trunkType = Bstr(TRUNKTYPE_WHATEVER);
5834 }
5835 break;
5836 }
5837#endif /* VBOX_WITH_CLOUD_NET */
5838
5839 default:
5840 AssertMsgFailed(("should not get here!\n"));
5841 break;
5842 }
5843
5844 /*
5845 * Attempt to attach the driver.
5846 */
5847 switch (eAttachmentType)
5848 {
5849 case NetworkAttachmentType_Null:
5850 break;
5851
5852 case NetworkAttachmentType_Bridged:
5853 case NetworkAttachmentType_Internal:
5854 case NetworkAttachmentType_HostOnly:
5855 case NetworkAttachmentType_NAT:
5856 case NetworkAttachmentType_Generic:
5857 case NetworkAttachmentType_NATNetwork:
5858#ifdef VBOX_WITH_CLOUD_NET
5859 case NetworkAttachmentType_Cloud:
5860#endif /* VBOX_WITH_CLOUD_NET */
5861 {
5862 if (SUCCEEDED(hrc) && RT_SUCCESS(rc))
5863 {
5864 if (fAttachDetach)
5865 {
5866 rc = PDMR3DriverAttach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/, NULL /* ppBase */);
5867 //AssertRC(rc);
5868 }
5869
5870 {
5871 /** @todo pritesh: get the dhcp server name from the
5872 * previous network configuration and then stop the server
5873 * else it may conflict with the dhcp server running with
5874 * the current attachment type
5875 */
5876 /* Stop the hostonly DHCP Server */
5877 }
5878
5879 /*
5880 * NAT networks start their DHCP server theirself, see NATNetwork::Start()
5881 */
5882 if ( !networkName.isEmpty()
5883 && eAttachmentType != NetworkAttachmentType_NATNetwork)
5884 {
5885 /*
5886 * Until we implement service reference counters DHCP Server will be stopped
5887 * by DHCPServerRunner destructor.
5888 */
5889 ComPtr<IDHCPServer> dhcpServer;
5890 hrc = virtualBox->FindDHCPServerByNetworkName(networkName.raw(),
5891 dhcpServer.asOutParam());
5892 if (SUCCEEDED(hrc))
5893 {
5894 /* there is a DHCP server available for this network */
5895 BOOL fEnabledDhcp;
5896 hrc = dhcpServer->COMGETTER(Enabled)(&fEnabledDhcp);
5897 if (FAILED(hrc))
5898 {
5899 LogRel(("DHCP svr: COMGETTER(Enabled) failed, hrc (%Rhrc)\n", hrc));
5900 H();
5901 }
5902
5903 if (fEnabledDhcp)
5904 hrc = dhcpServer->Start(trunkName.raw(),
5905 trunkType.raw());
5906 }
5907 else
5908 hrc = S_OK;
5909 }
5910 }
5911
5912 break;
5913 }
5914
5915 default:
5916 AssertMsgFailed(("should not get here!\n"));
5917 break;
5918 }
5919
5920 meAttachmentType[uInstance] = eAttachmentType;
5921 }
5922 catch (ConfigError &x)
5923 {
5924 // InsertConfig threw something:
5925 return x.m_vrc;
5926 }
5927
5928#undef H
5929
5930 return VINF_SUCCESS;
5931}
5932
5933
5934/**
5935 * Configures the serial port at the given CFGM node with the supplied parameters.
5936 *
5937 * @returns VBox status code.
5938 * @param pInst The instance CFGM node.
5939 * @param ePortMode The port mode to sue.
5940 * @param pszPath The serial port path.
5941 * @param fServer Flag whether the port should act as a server
5942 * for the pipe and TCP mode or connect as a client.
5943 */
5944int Console::i_configSerialPort(PCFGMNODE pInst, PortMode_T ePortMode, const char *pszPath, bool fServer)
5945{
5946 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
5947 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */
5948 PCFGMNODE pLunL1Cfg = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/Config */
5949
5950 try
5951 {
5952 InsertConfigNode(pInst, "LUN#0", &pLunL0);
5953 if (ePortMode == PortMode_HostPipe)
5954 {
5955 InsertConfigString(pLunL0, "Driver", "Char");
5956 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
5957 InsertConfigString(pLunL1, "Driver", "NamedPipe");
5958 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
5959 InsertConfigString(pLunL1Cfg, "Location", pszPath);
5960 InsertConfigInteger(pLunL1Cfg, "IsServer", fServer);
5961 }
5962 else if (ePortMode == PortMode_HostDevice)
5963 {
5964 InsertConfigString(pLunL0, "Driver", "Host Serial");
5965 InsertConfigNode(pLunL0, "Config", &pLunL1);
5966 InsertConfigString(pLunL1, "DevicePath", pszPath);
5967 }
5968 else if (ePortMode == PortMode_TCP)
5969 {
5970 InsertConfigString(pLunL0, "Driver", "Char");
5971 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
5972 InsertConfigString(pLunL1, "Driver", "TCP");
5973 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
5974 InsertConfigString(pLunL1Cfg, "Location", pszPath);
5975 InsertConfigInteger(pLunL1Cfg, "IsServer", fServer);
5976 }
5977 else if (ePortMode == PortMode_RawFile)
5978 {
5979 InsertConfigString(pLunL0, "Driver", "Char");
5980 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
5981 InsertConfigString(pLunL1, "Driver", "RawFile");
5982 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
5983 InsertConfigString(pLunL1Cfg, "Location", pszPath);
5984 }
5985 }
5986 catch (ConfigError &x)
5987 {
5988 /* InsertConfig threw something */
5989 return x.m_vrc;
5990 }
5991
5992 return VINF_SUCCESS;
5993}
5994
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