VirtualBox

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

Last change on this file since 80774 was 80729, checked in by vboxsync, 5 years ago

Main/ConsoleImpl2: Build fix if VBOX_WITH_VMSVGA is not defined.

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

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