VirtualBox

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

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

Build fixes for r136290.

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