VirtualBox

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

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

DnD/Main: Renamed GuestDnDInst() macro -> GUESTDNDINST().

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