VirtualBox

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

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

Main/Machine+StorageController+SystemProperties+Console: Add basic support for virtio-scsi storage controller.

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