VirtualBox

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

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

Main: removed obsolete HostWindowId

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette