VirtualBox

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

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

Main/Console: eliminate duplicate check

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