VirtualBox

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

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

ConsoleImpl2.cpp: nits.

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

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