VirtualBox

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

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

Shared Clipboard: VM startup fixes, hopefully also a bit more robust.

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