VirtualBox

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

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

Shared Clipboard/URI: Update.

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