VirtualBox

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

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

Copyright year updates by scm.

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

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