VirtualBox

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

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

OCI: (bugref:9469) cloud network integration code moved from Machine to Console, cloud network environment setup (cloud part).

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

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