VirtualBox

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

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

Forward ported 130474,130475,130477,130479. bugref:9453

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