VirtualBox

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

Last change on this file since 78750 was 78725, checked in by vboxsync, 6 years ago

Shared Clipboard/URI: Update.

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