VirtualBox

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

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

Runtime: Some renaming to stay consistent (*Get* always returns what is asked for while *Query* returns a status code and where to store the value on success is given as a pointer)

  • RTVfsFileGetSize -> RTVfsFileQuerySize
  • RTFileQuerySize -> RTFileQuerySizeByPath
  • RTFileGetSize -> RTFileQuerySize
  • RTFileGetSizeMaxEx -> RTFileQuerySizeMaxEx
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 245.8 KB
Line 
1/* $Id: ConsoleImpl2.cpp 80585 2019-09-04 14:05:50Z 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
3780 }
3781#endif
3782
3783 /* Custom VESA mode list */
3784 unsigned cModes = 0;
3785 for (unsigned iMode = 1; iMode <= 16; ++iMode)
3786 {
3787 char szExtraDataKey[sizeof("CustomVideoModeXX")];
3788 RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%u", iMode);
3789 hrc = ptrMachine->GetExtraData(Bstr(szExtraDataKey).raw(), bstr.asOutParam()); H();
3790 if (bstr.isEmpty())
3791 break;
3792 InsertConfigString(pCfg, szExtraDataKey, bstr);
3793 ++cModes;
3794 }
3795 InsertConfigInteger(pCfg, "CustomVideoModes", cModes);
3796
3797 /* VESA height reduction */
3798 ULONG ulHeightReduction;
3799 IFramebuffer *pFramebuffer = NULL;
3800 hrc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
3801 if (SUCCEEDED(hrc) && pFramebuffer)
3802 {
3803 hrc = pFramebuffer->COMGETTER(HeightReduction)(&ulHeightReduction); H();
3804 pFramebuffer->Release();
3805 pFramebuffer = NULL;
3806 }
3807 else
3808 {
3809 /* If framebuffer is not available, there is no height reduction. */
3810 ulHeightReduction = 0;
3811 }
3812 InsertConfigInteger(pCfg, "HeightReduction", ulHeightReduction);
3813
3814 /*
3815 * BIOS logo
3816 */
3817 BOOL fFadeIn;
3818 hrc = ptrBiosSettings->COMGETTER(LogoFadeIn)(&fFadeIn); H();
3819 InsertConfigInteger(pCfg, "FadeIn", fFadeIn ? 1 : 0);
3820 BOOL fFadeOut;
3821 hrc = ptrBiosSettings->COMGETTER(LogoFadeOut)(&fFadeOut); H();
3822 InsertConfigInteger(pCfg, "FadeOut", fFadeOut ? 1: 0);
3823 ULONG logoDisplayTime;
3824 hrc = ptrBiosSettings->COMGETTER(LogoDisplayTime)(&logoDisplayTime); H();
3825 InsertConfigInteger(pCfg, "LogoTime", logoDisplayTime);
3826 Bstr logoImagePath;
3827 hrc = ptrBiosSettings->COMGETTER(LogoImagePath)(logoImagePath.asOutParam()); H();
3828 InsertConfigString(pCfg, "LogoFile", Utf8Str(!logoImagePath.isEmpty() ? logoImagePath : "") );
3829
3830 /*
3831 * Boot menu
3832 */
3833 BIOSBootMenuMode_T eBootMenuMode;
3834 int iShowBootMenu;
3835 hrc = ptrBiosSettings->COMGETTER(BootMenuMode)(&eBootMenuMode); H();
3836 switch (eBootMenuMode)
3837 {
3838 case BIOSBootMenuMode_Disabled: iShowBootMenu = 0; break;
3839 case BIOSBootMenuMode_MenuOnly: iShowBootMenu = 1; break;
3840 default: iShowBootMenu = 2; break;
3841 }
3842 InsertConfigInteger(pCfg, "ShowBootMenu", iShowBootMenu);
3843
3844 /* Attach the display. */
3845 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3846 InsertConfigString(pLunL0, "Driver", "MainDisplay");
3847 InsertConfigNode(pLunL0, "Config", &pCfg);
3848 Display *pDisplay = mDisplay;
3849 InsertConfigInteger(pCfg, "Object", (uintptr_t)pDisplay);
3850 }
3851 catch (ConfigError &x)
3852 {
3853 // InsertConfig threw something:
3854 return x.m_vrc;
3855 }
3856
3857#undef H
3858
3859 return VINF_SUCCESS;
3860}
3861
3862
3863/**
3864 * Ellipsis to va_list wrapper for calling setVMRuntimeErrorCallback.
3865 */
3866void Console::i_atVMRuntimeErrorCallbackF(uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)
3867{
3868 va_list va;
3869 va_start(va, pszFormat);
3870 i_atVMRuntimeErrorCallback(NULL, this, fFlags, pszErrorId, pszFormat, va);
3871 va_end(va);
3872}
3873
3874/* XXX introduce RT format specifier */
3875static uint64_t formatDiskSize(uint64_t u64Size, const char **pszUnit)
3876{
3877 if (u64Size > INT64_C(5000)*_1G)
3878 {
3879 *pszUnit = "TB";
3880 return u64Size / _1T;
3881 }
3882 else if (u64Size > INT64_C(5000)*_1M)
3883 {
3884 *pszUnit = "GB";
3885 return u64Size / _1G;
3886 }
3887 else
3888 {
3889 *pszUnit = "MB";
3890 return u64Size / _1M;
3891 }
3892}
3893
3894/**
3895 * Checks the location of the given medium for known bugs affecting the usage
3896 * of the host I/O cache setting.
3897 *
3898 * @returns VBox status code.
3899 * @param pMedium The medium to check.
3900 * @param pfUseHostIOCache Where to store the suggested host I/O cache setting.
3901 */
3902int Console::i_checkMediumLocation(IMedium *pMedium, bool *pfUseHostIOCache)
3903{
3904#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
3905 /*
3906 * Some sanity checks.
3907 */
3908 RT_NOREF(pfUseHostIOCache);
3909 ComPtr<IMediumFormat> pMediumFormat;
3910 HRESULT hrc = pMedium->COMGETTER(MediumFormat)(pMediumFormat.asOutParam()); H();
3911 ULONG uCaps = 0;
3912 com::SafeArray <MediumFormatCapabilities_T> mediumFormatCap;
3913 hrc = pMediumFormat->COMGETTER(Capabilities)(ComSafeArrayAsOutParam(mediumFormatCap)); H();
3914
3915 for (ULONG j = 0; j < mediumFormatCap.size(); j++)
3916 uCaps |= mediumFormatCap[j];
3917
3918 if (uCaps & MediumFormatCapabilities_File)
3919 {
3920 Bstr strFile;
3921 hrc = pMedium->COMGETTER(Location)(strFile.asOutParam()); H();
3922 Utf8Str utfFile = Utf8Str(strFile);
3923 Bstr strSnap;
3924 ComPtr<IMachine> pMachine = i_machine();
3925 hrc = pMachine->COMGETTER(SnapshotFolder)(strSnap.asOutParam()); H();
3926 Utf8Str utfSnap = Utf8Str(strSnap);
3927 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
3928 RTFSTYPE enmFsTypeSnap = RTFSTYPE_UNKNOWN;
3929 int rc2 = RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
3930 AssertMsgRCReturn(rc2, ("Querying the file type of '%s' failed!\n", utfFile.c_str()), rc2);
3931 /* Ignore the error code. On error, the file system type is still 'unknown' so
3932 * none of the following paths are taken. This can happen for new VMs which
3933 * still don't have a snapshot folder. */
3934 (void)RTFsQueryType(utfSnap.c_str(), &enmFsTypeSnap);
3935 if (!mfSnapshotFolderDiskTypeShown)
3936 {
3937 LogRel(("File system of '%s' (snapshots) is %s\n",
3938 utfSnap.c_str(), RTFsTypeName(enmFsTypeSnap)));
3939 mfSnapshotFolderDiskTypeShown = true;
3940 }
3941 LogRel(("File system of '%s' is %s\n", utfFile.c_str(), RTFsTypeName(enmFsTypeFile)));
3942 LONG64 i64Size;
3943 hrc = pMedium->COMGETTER(LogicalSize)(&i64Size); H();
3944#ifdef RT_OS_WINDOWS
3945 if ( enmFsTypeFile == RTFSTYPE_FAT
3946 && i64Size >= _4G)
3947 {
3948 const char *pszUnit;
3949 uint64_t u64Print = formatDiskSize((uint64_t)i64Size, &pszUnit);
3950 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
3951 N_("The medium '%ls' has a logical size of %RU64%s "
3952 "but the file system the medium is located on seems "
3953 "to be FAT(32) which cannot handle files bigger than 4GB.\n"
3954 "We strongly recommend to put all your virtual disk images and "
3955 "the snapshot folder onto an NTFS partition"),
3956 strFile.raw(), u64Print, pszUnit);
3957 }
3958#else /* !RT_OS_WINDOWS */
3959 if ( enmFsTypeFile == RTFSTYPE_FAT
3960 || enmFsTypeFile == RTFSTYPE_EXT
3961 || enmFsTypeFile == RTFSTYPE_EXT2
3962 || enmFsTypeFile == RTFSTYPE_EXT3
3963 || enmFsTypeFile == RTFSTYPE_EXT4)
3964 {
3965 RTFILE file;
3966 int rc = RTFileOpen(&file, utfFile.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
3967 if (RT_SUCCESS(rc))
3968 {
3969 RTFOFF maxSize;
3970 /* Careful: This function will work only on selected local file systems! */
3971 rc = RTFileQueryMaxSizeEx(file, &maxSize);
3972 RTFileClose(file);
3973 if ( RT_SUCCESS(rc)
3974 && maxSize > 0
3975 && i64Size > (LONG64)maxSize)
3976 {
3977 const char *pszUnitSiz;
3978 const char *pszUnitMax;
3979 uint64_t u64PrintSiz = formatDiskSize((LONG64)i64Size, &pszUnitSiz);
3980 uint64_t u64PrintMax = formatDiskSize(maxSize, &pszUnitMax);
3981 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected", /* <= not exact but ... */
3982 N_("The medium '%ls' has a logical size of %RU64%s "
3983 "but the file system the medium is located on can "
3984 "only handle files up to %RU64%s in theory.\n"
3985 "We strongly recommend to put all your virtual disk "
3986 "images and the snapshot folder onto a proper "
3987 "file system (e.g. ext3) with a sufficient size"),
3988 strFile.raw(), u64PrintSiz, pszUnitSiz, u64PrintMax, pszUnitMax);
3989 }
3990 }
3991 }
3992#endif /* !RT_OS_WINDOWS */
3993
3994 /*
3995 * Snapshot folder:
3996 * Here we test only for a FAT partition as we had to create a dummy file otherwise
3997 */
3998 if ( enmFsTypeSnap == RTFSTYPE_FAT
3999 && i64Size >= _4G
4000 && !mfSnapshotFolderSizeWarningShown)
4001 {
4002 const char *pszUnit;
4003 uint64_t u64Print = formatDiskSize(i64Size, &pszUnit);
4004 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
4005#ifdef RT_OS_WINDOWS
4006 N_("The snapshot folder of this VM '%ls' seems to be located on "
4007 "a FAT(32) file system. The logical size of the medium '%ls' "
4008 "(%RU64%s) is bigger than the maximum file size this file "
4009 "system can handle (4GB).\n"
4010 "We strongly recommend to put all your virtual disk images and "
4011 "the snapshot folder onto an NTFS partition"),
4012#else
4013 N_("The snapshot folder of this VM '%ls' seems to be located on "
4014 "a FAT(32) file system. The logical size of the medium '%ls' "
4015 "(%RU64%s) is bigger than the maximum file size this file "
4016 "system can handle (4GB).\n"
4017 "We strongly recommend to put all your virtual disk images and "
4018 "the snapshot folder onto a proper file system (e.g. ext3)"),
4019#endif
4020 strSnap.raw(), strFile.raw(), u64Print, pszUnit);
4021 /* Show this particular warning only once */
4022 mfSnapshotFolderSizeWarningShown = true;
4023 }
4024
4025#ifdef RT_OS_LINUX
4026 /*
4027 * Ext4 bug: Check if the host I/O cache is disabled and the disk image is located
4028 * on an ext4 partition.
4029 * This bug apparently applies to the XFS file system as well.
4030 * Linux 2.6.36 is known to be fixed (tested with 2.6.36-rc4).
4031 */
4032
4033 char szOsRelease[128];
4034 int rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOsRelease, sizeof(szOsRelease));
4035 bool fKernelHasODirectBug = RT_FAILURE(rc)
4036 || (RTStrVersionCompare(szOsRelease, "2.6.36-rc4") < 0);
4037
4038 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
4039 && !*pfUseHostIOCache
4040 && fKernelHasODirectBug)
4041 {
4042 if ( enmFsTypeFile == RTFSTYPE_EXT4
4043 || enmFsTypeFile == RTFSTYPE_XFS)
4044 {
4045 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
4046 N_("The host I/O cache for at least one controller is disabled "
4047 "and the medium '%ls' for this VM "
4048 "is located on an %s partition. There is a known Linux "
4049 "kernel bug which can lead to the corruption of the virtual "
4050 "disk image under these conditions.\n"
4051 "Either enable the host I/O cache permanently in the VM "
4052 "settings or put the disk image and the snapshot folder "
4053 "onto a different file system.\n"
4054 "The host I/O cache will now be enabled for this medium"),
4055 strFile.raw(), enmFsTypeFile == RTFSTYPE_EXT4 ? "ext4" : "xfs");
4056 *pfUseHostIOCache = true;
4057 }
4058 else if ( ( enmFsTypeSnap == RTFSTYPE_EXT4
4059 || enmFsTypeSnap == RTFSTYPE_XFS)
4060 && !mfSnapshotFolderExt4WarningShown)
4061 {
4062 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
4063 N_("The host I/O cache for at least one controller is disabled "
4064 "and the snapshot folder for this VM "
4065 "is located on an %s partition. There is a known Linux "
4066 "kernel bug which can lead to the corruption of the virtual "
4067 "disk image under these conditions.\n"
4068 "Either enable the host I/O cache permanently in the VM "
4069 "settings or put the disk image and the snapshot folder "
4070 "onto a different file system.\n"
4071 "The host I/O cache will now be enabled for this medium"),
4072 enmFsTypeSnap == RTFSTYPE_EXT4 ? "ext4" : "xfs");
4073 *pfUseHostIOCache = true;
4074 mfSnapshotFolderExt4WarningShown = true;
4075 }
4076 }
4077
4078 /*
4079 * 2.6.18 bug: Check if the host I/O cache is disabled and the host is running
4080 * Linux 2.6.18. See @bugref{8690}. Apparently the same problem as
4081 * documented in https://lkml.org/lkml/2007/2/1/14. We saw such
4082 * kernel oopses on Linux 2.6.18-416.el5. We don't know when this
4083 * was fixed but we _know_ that 2.6.18 EL5 kernels are affected.
4084 */
4085 bool fKernelAsyncUnreliable = RT_FAILURE(rc)
4086 || (RTStrVersionCompare(szOsRelease, "2.6.19") < 0);
4087 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
4088 && !*pfUseHostIOCache
4089 && fKernelAsyncUnreliable)
4090 {
4091 i_atVMRuntimeErrorCallbackF(0, "Linux2618TooOld",
4092 N_("The host I/O cache for at least one controller is disabled. "
4093 "There is a known Linux kernel bug which can lead to kernel "
4094 "oopses under heavy load. To our knowledge this bug affects "
4095 "all 2.6.18 kernels.\n"
4096 "Either enable the host I/O cache permanently in the VM "
4097 "settings or switch to a newer host kernel.\n"
4098 "The host I/O cache will now be enabled for this medium"));
4099 *pfUseHostIOCache = true;
4100 }
4101#endif
4102 }
4103#undef H
4104
4105 return VINF_SUCCESS;
4106}
4107
4108/**
4109 * Unmounts the specified medium from the specified device.
4110 *
4111 * @returns VBox status code.
4112 * @param pUVM The usermode VM handle.
4113 * @param enmBus The storage bus.
4114 * @param enmDevType The device type.
4115 * @param pcszDevice The device emulation.
4116 * @param uInstance Instance of the device.
4117 * @param uLUN The LUN on the device.
4118 * @param fForceUnmount Whether to force unmounting.
4119 */
4120int Console::i_unmountMediumFromGuest(PUVM pUVM, StorageBus_T enmBus, DeviceType_T enmDevType,
4121 const char *pcszDevice, unsigned uInstance, unsigned uLUN,
4122 bool fForceUnmount)
4123{
4124 /* Unmount existing media only for floppy and DVD drives. */
4125 int rc = VINF_SUCCESS;
4126 PPDMIBASE pBase;
4127 if (enmBus == StorageBus_USB)
4128 rc = PDMR3UsbQueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
4129 else if ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI || enmBus == StorageBus_VirtioSCSI)
4130 || (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD))
4131 rc = PDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
4132 else /* IDE or Floppy */
4133 rc = PDMR3QueryLun(pUVM, pcszDevice, uInstance, uLUN, &pBase);
4134
4135 if (RT_FAILURE(rc))
4136 {
4137 if (rc == VERR_PDM_LUN_NOT_FOUND || rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4138 rc = VINF_SUCCESS;
4139 AssertRC(rc);
4140 }
4141 else
4142 {
4143 PPDMIMOUNT pIMount = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMOUNT);
4144 AssertReturn(pIMount, VERR_INVALID_POINTER);
4145
4146 /* Unmount the media (but do not eject the medium!) */
4147 rc = pIMount->pfnUnmount(pIMount, fForceUnmount, false /*=fEject*/);
4148 if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
4149 rc = VINF_SUCCESS;
4150 /* for example if the medium is locked */
4151 else if (RT_FAILURE(rc))
4152 return rc;
4153 }
4154
4155 return rc;
4156}
4157
4158/**
4159 * Removes the currently attached medium driver form the specified device
4160 * taking care of the controlelr specific configs wrt. to the attached driver chain.
4161 *
4162 * @returns VBox status code.
4163 * @param pCtlInst The controler instance node in the CFGM tree.
4164 * @param pcszDevice The device name.
4165 * @param uInstance The device instance.
4166 * @param uLUN The device LUN.
4167 * @param enmBus The storage bus.
4168 * @param fAttachDetach Flag whether this is a change while the VM is running
4169 * @param fHotplug Flag whether the guest should be notified about the device change.
4170 * @param fForceUnmount Flag whether to force unmounting the medium even if it is locked.
4171 * @param pUVM The usermode VM handle.
4172 * @param enmDevType The device type.
4173 * @param ppLunL0 Where to store the node to attach the new config to on success.
4174 */
4175int Console::i_removeMediumDriverFromVm(PCFGMNODE pCtlInst,
4176 const char *pcszDevice,
4177 unsigned uInstance,
4178 unsigned uLUN,
4179 StorageBus_T enmBus,
4180 bool fAttachDetach,
4181 bool fHotplug,
4182 bool fForceUnmount,
4183 PUVM pUVM,
4184 DeviceType_T enmDevType,
4185 PCFGMNODE *ppLunL0)
4186{
4187 int rc = VINF_SUCCESS;
4188 bool fAddLun = false;
4189
4190 /* First check if the LUN already exists. */
4191 PCFGMNODE pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
4192 AssertReturn(!VALID_PTR(pLunL0) || fAttachDetach, VERR_INTERNAL_ERROR);
4193
4194 if (pLunL0)
4195 {
4196 /*
4197 * Unmount the currently mounted medium if we don't just hot remove the
4198 * complete device (SATA) and it supports unmounting (DVD).
4199 */
4200 if ( (enmDevType != DeviceType_HardDisk)
4201 && !fHotplug)
4202 {
4203 rc = i_unmountMediumFromGuest(pUVM, enmBus, enmDevType, pcszDevice,
4204 uInstance, uLUN, fForceUnmount);
4205 if (RT_FAILURE(rc))
4206 return rc;
4207 }
4208
4209 /*
4210 * Don't detach the SCSI driver when unmounting the current medium
4211 * (we are not ripping out the device but only eject the medium).
4212 */
4213 char *pszDriverDetach = NULL;
4214 if ( !fHotplug
4215 && ( (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD)
4216 || enmBus == StorageBus_SAS
4217 || enmBus == StorageBus_SCSI
4218 || enmBus == StorageBus_VirtioSCSI
4219 || enmBus == StorageBus_USB))
4220 {
4221 /* Get the current attached driver we have to detach. */
4222 PCFGMNODE pDrvLun = CFGMR3GetChildF(pCtlInst, "LUN#%u/AttachedDriver/", uLUN);
4223 if (pDrvLun)
4224 {
4225 char szDriver[128];
4226 RT_ZERO(szDriver);
4227 rc = CFGMR3QueryString(pDrvLun, "Driver", &szDriver[0], sizeof(szDriver));
4228 if (RT_SUCCESS(rc))
4229 pszDriverDetach = RTStrDup(&szDriver[0]);
4230
4231 pLunL0 = pDrvLun;
4232 }
4233 }
4234
4235 if (enmBus == StorageBus_USB)
4236 rc = PDMR3UsbDriverDetach(pUVM, pcszDevice, uInstance, uLUN,
4237 pszDriverDetach, 0 /* iOccurence */,
4238 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
4239 else
4240 rc = PDMR3DriverDetach(pUVM, pcszDevice, uInstance, uLUN,
4241 pszDriverDetach, 0 /* iOccurence */,
4242 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
4243
4244 if (pszDriverDetach)
4245 {
4246 RTStrFree(pszDriverDetach);
4247 /* Remove the complete node and create new for the new config. */
4248 CFGMR3RemoveNode(pLunL0);
4249 pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
4250 if (pLunL0)
4251 {
4252 try
4253 {
4254 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4255 }
4256 catch (ConfigError &x)
4257 {
4258 // InsertConfig threw something:
4259 return x.m_vrc;
4260 }
4261 }
4262 }
4263 if (rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4264 rc = VINF_SUCCESS;
4265 AssertRCReturn(rc, rc);
4266
4267 /*
4268 * Don't remove the LUN except for IDE/floppy/NVMe (which connects directly to the medium driver
4269 * even for DVD devices) or if there is a hotplug event which rips out the complete device.
4270 */
4271 if ( fHotplug
4272 || enmBus == StorageBus_IDE
4273 || enmBus == StorageBus_Floppy
4274 || enmBus == StorageBus_PCIe
4275 || (enmBus == StorageBus_SATA && enmDevType != DeviceType_DVD))
4276 {
4277 fAddLun = true;
4278 CFGMR3RemoveNode(pLunL0);
4279 }
4280 }
4281 else
4282 fAddLun = true;
4283
4284 try
4285 {
4286 if (fAddLun)
4287 InsertConfigNode(pCtlInst, Utf8StrFmt("LUN#%u", uLUN).c_str(), &pLunL0);
4288 }
4289 catch (ConfigError &x)
4290 {
4291 // InsertConfig threw something:
4292 return x.m_vrc;
4293 }
4294
4295 if (ppLunL0)
4296 *ppLunL0 = pLunL0;
4297
4298 return rc;
4299}
4300
4301int Console::i_configMediumAttachment(const char *pcszDevice,
4302 unsigned uInstance,
4303 StorageBus_T enmBus,
4304 bool fUseHostIOCache,
4305 bool fBuiltinIOCache,
4306 bool fInsertDiskIntegrityDrv,
4307 bool fSetupMerge,
4308 unsigned uMergeSource,
4309 unsigned uMergeTarget,
4310 IMediumAttachment *pMediumAtt,
4311 MachineState_T aMachineState,
4312 HRESULT *phrc,
4313 bool fAttachDetach,
4314 bool fForceUnmount,
4315 bool fHotplug,
4316 PUVM pUVM,
4317 DeviceType_T *paLedDevType,
4318 PCFGMNODE *ppLunL0)
4319{
4320 // InsertConfig* throws
4321 try
4322 {
4323 int rc = VINF_SUCCESS;
4324 HRESULT hrc;
4325 Bstr bstr;
4326 PCFGMNODE pCtlInst = NULL;
4327
4328// #define RC_CHECK() AssertMsgReturn(RT_SUCCESS(rc), ("rc=%Rrc\n", rc), rc)
4329#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4330
4331 LONG lDev;
4332 hrc = pMediumAtt->COMGETTER(Device)(&lDev); H();
4333 LONG lPort;
4334 hrc = pMediumAtt->COMGETTER(Port)(&lPort); H();
4335 DeviceType_T lType;
4336 hrc = pMediumAtt->COMGETTER(Type)(&lType); H();
4337 BOOL fNonRotational;
4338 hrc = pMediumAtt->COMGETTER(NonRotational)(&fNonRotational); H();
4339 BOOL fDiscard;
4340 hrc = pMediumAtt->COMGETTER(Discard)(&fDiscard); H();
4341
4342 if (lType == DeviceType_DVD)
4343 fInsertDiskIntegrityDrv = false;
4344
4345 unsigned uLUN;
4346 PCFGMNODE pLunL0 = NULL;
4347 hrc = Console::i_storageBusPortDeviceToLun(enmBus, lPort, lDev, uLUN); H();
4348
4349 /* Determine the base path for the device instance. */
4350 if (enmBus != StorageBus_USB)
4351 pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "Devices/%s/%u/", pcszDevice, uInstance);
4352 else
4353 {
4354 /* If we hotplug a USB device create a new CFGM tree. */
4355 if (!fHotplug)
4356 pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "USB/%s/", pcszDevice);
4357 else
4358 pCtlInst = CFGMR3CreateTree(pUVM);
4359 }
4360 AssertReturn(pCtlInst, VERR_INTERNAL_ERROR);
4361
4362 if (enmBus == StorageBus_USB)
4363 {
4364 PCFGMNODE pCfg = NULL;
4365
4366 /* Create correct instance. */
4367 if (!fHotplug)
4368 {
4369 if (!fAttachDetach)
4370 InsertConfigNode(pCtlInst, Utf8StrFmt("%d", lPort).c_str(), &pCtlInst);
4371 else
4372 pCtlInst = CFGMR3GetChildF(pCtlInst, "%d/", lPort);
4373 }
4374
4375 if (!fAttachDetach)
4376 InsertConfigNode(pCtlInst, "Config", &pCfg);
4377
4378 uInstance = lPort; /* Overwrite uInstance with the correct one. */
4379
4380 if (!fHotplug && !fAttachDetach)
4381 {
4382 char aszUuid[RTUUID_STR_LENGTH + 1];
4383 USBStorageDevice UsbMsd = USBStorageDevice();
4384
4385 memset(aszUuid, 0, sizeof(aszUuid));
4386 rc = RTUuidCreate(&UsbMsd.mUuid);
4387 AssertRCReturn(rc, rc);
4388 rc = RTUuidToStr(&UsbMsd.mUuid, aszUuid, sizeof(aszUuid));
4389 AssertRCReturn(rc, rc);
4390
4391 UsbMsd.iPort = uInstance;
4392
4393 InsertConfigString(pCtlInst, "UUID", aszUuid);
4394 mUSBStorageDevices.push_back(UsbMsd);
4395
4396 /** @todo No LED after hotplugging. */
4397 /* Attach the status driver */
4398 Assert(cLedUsb >= 8);
4399 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedUsb], 0, 7,
4400 &mapMediumAttachments, pcszDevice, 0);
4401 paLedDevType = &maStorageDevType[iLedUsb];
4402 }
4403 }
4404
4405 rc = i_removeMediumDriverFromVm(pCtlInst, pcszDevice, uInstance, uLUN, enmBus, fAttachDetach,
4406 fHotplug, fForceUnmount, pUVM, lType, &pLunL0);
4407 if (RT_FAILURE(rc))
4408 return rc;
4409 if (ppLunL0)
4410 *ppLunL0 = pLunL0;
4411
4412 Utf8Str devicePath = Utf8StrFmt("%s/%u/LUN#%u", pcszDevice, uInstance, uLUN);
4413 mapMediumAttachments[devicePath] = pMediumAtt;
4414
4415 ComPtr<IMedium> pMedium;
4416 hrc = pMediumAtt->COMGETTER(Medium)(pMedium.asOutParam()); H();
4417
4418 /*
4419 * 1. Only check this for hard disk images.
4420 * 2. Only check during VM creation and not later, especially not during
4421 * taking an online snapshot!
4422 */
4423 if ( lType == DeviceType_HardDisk
4424 && ( aMachineState == MachineState_Starting
4425 || aMachineState == MachineState_Restoring))
4426 {
4427 rc = i_checkMediumLocation(pMedium, &fUseHostIOCache);
4428 if (RT_FAILURE(rc))
4429 return rc;
4430 }
4431
4432 BOOL fPassthrough = FALSE;
4433 if (pMedium)
4434 {
4435 BOOL fHostDrive;
4436 hrc = pMedium->COMGETTER(HostDrive)(&fHostDrive); H();
4437 if ( ( lType == DeviceType_DVD
4438 || lType == DeviceType_Floppy)
4439 && !fHostDrive)
4440 {
4441 /*
4442 * Informative logging.
4443 */
4444 Bstr strFile;
4445 hrc = pMedium->COMGETTER(Location)(strFile.asOutParam()); H();
4446 Utf8Str utfFile = Utf8Str(strFile);
4447 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
4448 (void)RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
4449 LogRel(("File system of '%s' (%s) is %s\n",
4450 utfFile.c_str(), lType == DeviceType_DVD ? "DVD" : "Floppy",
4451 RTFsTypeName(enmFsTypeFile)));
4452 }
4453
4454 if (fHostDrive)
4455 {
4456 hrc = pMediumAtt->COMGETTER(Passthrough)(&fPassthrough); H();
4457 }
4458 }
4459
4460 ComObjPtr<IBandwidthGroup> pBwGroup;
4461 Bstr strBwGroup;
4462 hrc = pMediumAtt->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
4463
4464 if (!pBwGroup.isNull())
4465 {
4466 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
4467 }
4468
4469 /*
4470 * Insert the SCSI driver for hotplug events on the SCSI/USB based storage controllers
4471 * or for SATA if the new device is a CD/DVD drive.
4472 */
4473 if ( (fHotplug || !fAttachDetach)
4474 && ( (enmBus == StorageBus_SCSI || enmBus == StorageBus_SAS || enmBus == StorageBus_USB || enmBus == StorageBus_VirtioSCSI)
4475 || (enmBus == StorageBus_SATA && lType == DeviceType_DVD && !fPassthrough)))
4476 {
4477 InsertConfigString(pLunL0, "Driver", "SCSI");
4478 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4479 }
4480
4481 rc = i_configMedium(pLunL0,
4482 !!fPassthrough,
4483 lType,
4484 fUseHostIOCache,
4485 fBuiltinIOCache,
4486 fInsertDiskIntegrityDrv,
4487 fSetupMerge,
4488 uMergeSource,
4489 uMergeTarget,
4490 strBwGroup.isEmpty() ? NULL : Utf8Str(strBwGroup).c_str(),
4491 !!fDiscard,
4492 !!fNonRotational,
4493 pMedium,
4494 aMachineState,
4495 phrc);
4496 if (RT_FAILURE(rc))
4497 return rc;
4498
4499 if (fAttachDetach)
4500 {
4501 /* Attach the new driver. */
4502 if (enmBus == StorageBus_USB)
4503 {
4504 if (fHotplug)
4505 {
4506 USBStorageDevice UsbMsd = USBStorageDevice();
4507 RTUuidCreate(&UsbMsd.mUuid);
4508 UsbMsd.iPort = uInstance;
4509 rc = PDMR3UsbCreateEmulatedDevice(pUVM, pcszDevice, pCtlInst, &UsbMsd.mUuid, NULL);
4510 if (RT_SUCCESS(rc))
4511 mUSBStorageDevices.push_back(UsbMsd);
4512 }
4513 else
4514 rc = PDMR3UsbDriverAttach(pUVM, pcszDevice, uInstance, uLUN,
4515 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4516 }
4517 else if ( !fHotplug
4518 && ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI || enmBus == StorageBus_VirtioSCSI)
4519 || (enmBus == StorageBus_SATA && lType == DeviceType_DVD)))
4520 rc = PDMR3DriverAttach(pUVM, pcszDevice, uInstance, uLUN,
4521 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4522 else
4523 rc = PDMR3DeviceAttach(pUVM, pcszDevice, uInstance, uLUN,
4524 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4525 AssertRCReturn(rc, rc);
4526
4527 /*
4528 * Make the secret key helper interface known to the VD driver if it is attached,
4529 * so we can get notified about missing keys.
4530 */
4531 PPDMIBASE pIBase = NULL;
4532 rc = PDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "VD", &pIBase);
4533 if (RT_SUCCESS(rc) && pIBase)
4534 {
4535 PPDMIMEDIA pIMedium = (PPDMIMEDIA)pIBase->pfnQueryInterface(pIBase, PDMIMEDIA_IID);
4536 if (pIMedium)
4537 {
4538 rc = pIMedium->pfnSetSecKeyIf(pIMedium, mpIfSecKey, mpIfSecKeyHlp);
4539 Assert(RT_SUCCESS(rc) || rc == VERR_NOT_SUPPORTED);
4540 }
4541 }
4542
4543 /* There is no need to handle removable medium mounting, as we
4544 * unconditionally replace everthing including the block driver level.
4545 * This means the new medium will be picked up automatically. */
4546 }
4547
4548 if (paLedDevType)
4549 paLedDevType[uLUN] = lType;
4550
4551 /* Dump the changed LUN if possible, dump the complete device otherwise */
4552 if ( aMachineState != MachineState_Starting
4553 && aMachineState != MachineState_Restoring)
4554 CFGMR3Dump(pLunL0 ? pLunL0 : pCtlInst);
4555 }
4556 catch (ConfigError &x)
4557 {
4558 // InsertConfig threw something:
4559 return x.m_vrc;
4560 }
4561
4562#undef H
4563
4564 return VINF_SUCCESS;
4565}
4566
4567int Console::i_configMedium(PCFGMNODE pLunL0,
4568 bool fPassthrough,
4569 DeviceType_T enmType,
4570 bool fUseHostIOCache,
4571 bool fBuiltinIOCache,
4572 bool fInsertDiskIntegrityDrv,
4573 bool fSetupMerge,
4574 unsigned uMergeSource,
4575 unsigned uMergeTarget,
4576 const char *pcszBwGroup,
4577 bool fDiscard,
4578 bool fNonRotational,
4579 IMedium *pMedium,
4580 MachineState_T aMachineState,
4581 HRESULT *phrc)
4582{
4583 // InsertConfig* throws
4584 try
4585 {
4586 HRESULT hrc;
4587 Bstr bstr;
4588 PCFGMNODE pCfg = NULL;
4589
4590#define H() \
4591 AssertMsgReturnStmt(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), if (phrc) *phrc = hrc, Global::vboxStatusCodeFromCOM(hrc))
4592
4593
4594 BOOL fHostDrive = FALSE;
4595 MediumType_T mediumType = MediumType_Normal;
4596 if (pMedium)
4597 {
4598 hrc = pMedium->COMGETTER(HostDrive)(&fHostDrive); H();
4599 hrc = pMedium->COMGETTER(Type)(&mediumType); H();
4600 }
4601
4602 if (fHostDrive)
4603 {
4604 Assert(pMedium);
4605 if (enmType == DeviceType_DVD)
4606 {
4607 InsertConfigString(pLunL0, "Driver", "HostDVD");
4608 InsertConfigNode(pLunL0, "Config", &pCfg);
4609
4610 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4611 InsertConfigString(pCfg, "Path", bstr);
4612
4613 InsertConfigInteger(pCfg, "Passthrough", fPassthrough);
4614 }
4615 else if (enmType == DeviceType_Floppy)
4616 {
4617 InsertConfigString(pLunL0, "Driver", "HostFloppy");
4618 InsertConfigNode(pLunL0, "Config", &pCfg);
4619
4620 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4621 InsertConfigString(pCfg, "Path", bstr);
4622 }
4623 }
4624 else
4625 {
4626 if (fInsertDiskIntegrityDrv)
4627 {
4628 /*
4629 * The actual configuration is done through CFGM extra data
4630 * for each inserted driver separately.
4631 */
4632 InsertConfigString(pLunL0, "Driver", "DiskIntegrity");
4633 InsertConfigNode(pLunL0, "Config", &pCfg);
4634 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4635 }
4636
4637 InsertConfigString(pLunL0, "Driver", "VD");
4638 InsertConfigNode(pLunL0, "Config", &pCfg);
4639 switch (enmType)
4640 {
4641 case DeviceType_DVD:
4642 InsertConfigString(pCfg, "Type", "DVD");
4643 InsertConfigInteger(pCfg, "Mountable", 1);
4644 break;
4645 case DeviceType_Floppy:
4646 InsertConfigString(pCfg, "Type", "Floppy 1.44");
4647 InsertConfigInteger(pCfg, "Mountable", 1);
4648 break;
4649 case DeviceType_HardDisk:
4650 default:
4651 InsertConfigString(pCfg, "Type", "HardDisk");
4652 InsertConfigInteger(pCfg, "Mountable", 0);
4653 }
4654
4655 if ( pMedium
4656 && ( enmType == DeviceType_DVD
4657 || enmType == DeviceType_Floppy)
4658 )
4659 {
4660 // if this medium represents an ISO image and this image is inaccessible,
4661 // the ignore it instead of causing a failure; this can happen when we
4662 // restore a VM state and the ISO has disappeared, e.g. because the Guest
4663 // Additions were mounted and the user upgraded VirtualBox. Previously
4664 // we failed on startup, but that's not good because the only way out then
4665 // would be to discard the VM state...
4666 MediumState_T mediumState;
4667 hrc = pMedium->RefreshState(&mediumState); H();
4668 if (mediumState == MediumState_Inaccessible)
4669 {
4670 Bstr loc;
4671 hrc = pMedium->COMGETTER(Location)(loc.asOutParam()); H();
4672 i_atVMRuntimeErrorCallbackF(0, "DvdOrFloppyImageInaccessible",
4673 "The image file '%ls' is inaccessible and is being ignored. "
4674 "Please select a different image file for the virtual %s drive.",
4675 loc.raw(),
4676 enmType == DeviceType_DVD ? "DVD" : "floppy");
4677 pMedium = NULL;
4678 }
4679 }
4680
4681 if (pMedium)
4682 {
4683 /* Start with length of parent chain, as the list is reversed */
4684 unsigned uImage = 0;
4685 IMedium *pTmp = pMedium;
4686 while (pTmp)
4687 {
4688 uImage++;
4689 hrc = pTmp->COMGETTER(Parent)(&pTmp); H();
4690 }
4691 /* Index of last image */
4692 uImage--;
4693
4694# ifdef VBOX_WITH_EXTPACK
4695 if (mptrExtPackManager->i_isExtPackUsable(ORACLE_PUEL_EXTPACK_NAME))
4696 {
4697 /* Configure loading the VDPlugin. */
4698 static const char s_szVDPlugin[] = "VDPluginCrypt";
4699 PCFGMNODE pCfgPlugins = NULL;
4700 PCFGMNODE pCfgPlugin = NULL;
4701 Utf8Str strPlugin;
4702 hrc = mptrExtPackManager->i_getLibraryPathForExtPack(s_szVDPlugin, ORACLE_PUEL_EXTPACK_NAME, &strPlugin);
4703 // Don't fail, this is optional!
4704 if (SUCCEEDED(hrc))
4705 {
4706 InsertConfigNode(pCfg, "Plugins", &pCfgPlugins);
4707 InsertConfigNode(pCfgPlugins, s_szVDPlugin, &pCfgPlugin);
4708 InsertConfigString(pCfgPlugin, "Path", strPlugin.c_str());
4709 }
4710 }
4711# endif
4712
4713 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4714 InsertConfigString(pCfg, "Path", bstr);
4715
4716 hrc = pMedium->COMGETTER(Format)(bstr.asOutParam()); H();
4717 InsertConfigString(pCfg, "Format", bstr);
4718
4719 if (mediumType == MediumType_Readonly)
4720 InsertConfigInteger(pCfg, "ReadOnly", 1);
4721 else if (enmType == DeviceType_Floppy)
4722 InsertConfigInteger(pCfg, "MaybeReadOnly", 1);
4723
4724 /* Start without exclusive write access to the images. */
4725 /** @todo Live Migration: I don't quite like this, we risk screwing up when
4726 * we're resuming the VM if some 3rd dude have any of the VDIs open
4727 * with write sharing denied. However, if the two VMs are sharing a
4728 * image it really is necessary....
4729 *
4730 * So, on the "lock-media" command, the target teleporter should also
4731 * make DrvVD undo TempReadOnly. It gets interesting if we fail after
4732 * that. Grumble. */
4733 if ( enmType == DeviceType_HardDisk
4734 && aMachineState == MachineState_TeleportingIn)
4735 InsertConfigInteger(pCfg, "TempReadOnly", 1);
4736
4737 /* Flag for opening the medium for sharing between VMs. This
4738 * is done at the moment only for the first (and only) medium
4739 * in the chain, as shared media can have no diffs. */
4740 if (mediumType == MediumType_Shareable)
4741 InsertConfigInteger(pCfg, "Shareable", 1);
4742
4743 if (!fUseHostIOCache)
4744 {
4745 InsertConfigInteger(pCfg, "UseNewIo", 1);
4746 /*
4747 * Activate the builtin I/O cache for harddisks only.
4748 * It caches writes only which doesn't make sense for DVD drives
4749 * and just increases the overhead.
4750 */
4751 if ( fBuiltinIOCache
4752 && (enmType == DeviceType_HardDisk))
4753 InsertConfigInteger(pCfg, "BlockCache", 1);
4754 }
4755
4756 if (fSetupMerge)
4757 {
4758 InsertConfigInteger(pCfg, "SetupMerge", 1);
4759 if (uImage == uMergeSource)
4760 InsertConfigInteger(pCfg, "MergeSource", 1);
4761 else if (uImage == uMergeTarget)
4762 InsertConfigInteger(pCfg, "MergeTarget", 1);
4763 }
4764
4765 if (pcszBwGroup)
4766 InsertConfigString(pCfg, "BwGroup", pcszBwGroup);
4767
4768 if (fDiscard)
4769 InsertConfigInteger(pCfg, "Discard", 1);
4770
4771 if (fNonRotational)
4772 InsertConfigInteger(pCfg, "NonRotationalMedium", 1);
4773
4774 /* Pass all custom parameters. */
4775 bool fHostIP = true;
4776 bool fEncrypted = false;
4777 hrc = i_configMediumProperties(pCfg, pMedium, &fHostIP, &fEncrypted); H();
4778
4779 /* Create an inverted list of parents. */
4780 uImage--;
4781 IMedium *pParentMedium = pMedium;
4782 for (PCFGMNODE pParent = pCfg;; uImage--)
4783 {
4784 hrc = pParentMedium->COMGETTER(Parent)(&pMedium); H();
4785 if (!pMedium)
4786 break;
4787
4788 PCFGMNODE pCur;
4789 InsertConfigNode(pParent, "Parent", &pCur);
4790 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4791 InsertConfigString(pCur, "Path", bstr);
4792
4793 hrc = pMedium->COMGETTER(Format)(bstr.asOutParam()); H();
4794 InsertConfigString(pCur, "Format", bstr);
4795
4796 if (fSetupMerge)
4797 {
4798 if (uImage == uMergeSource)
4799 InsertConfigInteger(pCur, "MergeSource", 1);
4800 else if (uImage == uMergeTarget)
4801 InsertConfigInteger(pCur, "MergeTarget", 1);
4802 }
4803
4804 /* Configure medium properties. */
4805 hrc = i_configMediumProperties(pCur, pMedium, &fHostIP, &fEncrypted); H();
4806
4807 /* next */
4808 pParent = pCur;
4809 pParentMedium = pMedium;
4810 }
4811
4812 /* Custom code: put marker to not use host IP stack to driver
4813 * configuration node. Simplifies life of DrvVD a bit. */
4814 if (!fHostIP)
4815 InsertConfigInteger(pCfg, "HostIPStack", 0);
4816
4817 if (fEncrypted)
4818 m_cDisksEncrypted++;
4819 }
4820 else
4821 {
4822 /* Set empty drive flag for DVD or floppy without media. */
4823 if ( enmType == DeviceType_DVD
4824 || enmType == DeviceType_Floppy)
4825 InsertConfigInteger(pCfg, "EmptyDrive", 1);
4826 }
4827 }
4828#undef H
4829 }
4830 catch (ConfigError &x)
4831 {
4832 // InsertConfig threw something:
4833 return x.m_vrc;
4834 }
4835
4836 return VINF_SUCCESS;
4837}
4838
4839/**
4840 * Adds the medium properties to the CFGM tree.
4841 *
4842 * @returns VBox status code.
4843 * @param pCur The current CFGM node.
4844 * @param pMedium The medium object to configure.
4845 * @param pfHostIP Where to return the value of the \"HostIPStack\" property if found.
4846 * @param pfEncrypted Where to return whether the medium is encrypted.
4847 */
4848int Console::i_configMediumProperties(PCFGMNODE pCur, IMedium *pMedium, bool *pfHostIP, bool *pfEncrypted)
4849{
4850 /* Pass all custom parameters. */
4851 SafeArray<BSTR> aNames;
4852 SafeArray<BSTR> aValues;
4853 HRESULT hrc = pMedium->GetProperties(NULL, ComSafeArrayAsOutParam(aNames),
4854 ComSafeArrayAsOutParam(aValues));
4855
4856 if ( SUCCEEDED(hrc)
4857 && aNames.size() != 0)
4858 {
4859 PCFGMNODE pVDC;
4860 InsertConfigNode(pCur, "VDConfig", &pVDC);
4861 for (size_t ii = 0; ii < aNames.size(); ++ii)
4862 {
4863 if (aValues[ii] && *aValues[ii])
4864 {
4865 Utf8Str name = aNames[ii];
4866 Utf8Str value = aValues[ii];
4867 size_t offSlash = name.find("/", 0);
4868 if ( offSlash != name.npos
4869 && !name.startsWith("Special/"))
4870 {
4871 com::Utf8Str strFilter;
4872 com::Utf8Str strKey;
4873
4874 hrc = strFilter.assignEx(name, 0, offSlash);
4875 if (FAILED(hrc))
4876 break;
4877
4878 hrc = strKey.assignEx(name, offSlash + 1, name.length() - offSlash - 1); /* Skip slash */
4879 if (FAILED(hrc))
4880 break;
4881
4882 PCFGMNODE pCfgFilterConfig = CFGMR3GetChild(pVDC, strFilter.c_str());
4883 if (!pCfgFilterConfig)
4884 InsertConfigNode(pVDC, strFilter.c_str(), &pCfgFilterConfig);
4885
4886 InsertConfigString(pCfgFilterConfig, strKey.c_str(), value);
4887 }
4888 else
4889 {
4890 InsertConfigString(pVDC, name.c_str(), value);
4891 if ( name.compare("HostIPStack") == 0
4892 && value.compare("0") == 0)
4893 *pfHostIP = false;
4894 }
4895
4896 if ( name.compare("CRYPT/KeyId") == 0
4897 && pfEncrypted)
4898 *pfEncrypted = true;
4899 }
4900 }
4901 }
4902
4903 return hrc;
4904}
4905
4906
4907/**
4908 * Construct the Network configuration tree
4909 *
4910 * @returns VBox status code.
4911 *
4912 * @param pszDevice The PDM device name.
4913 * @param uInstance The PDM device instance.
4914 * @param uLun The PDM LUN number of the drive.
4915 * @param aNetworkAdapter The network adapter whose attachment needs to be changed
4916 * @param pCfg Configuration node for the device
4917 * @param pLunL0 To store the pointer to the LUN#0.
4918 * @param pInst The instance CFGM node
4919 * @param fAttachDetach To determine if the network attachment should
4920 * be attached/detached after/before
4921 * configuration.
4922 * @param fIgnoreConnectFailure
4923 * True if connection failures should be ignored
4924 * (makes only sense for bridged/host-only networks).
4925 *
4926 * @note Locks this object for writing.
4927 * @thread EMT
4928 */
4929int Console::i_configNetwork(const char *pszDevice,
4930 unsigned uInstance,
4931 unsigned uLun,
4932 INetworkAdapter *aNetworkAdapter,
4933 PCFGMNODE pCfg,
4934 PCFGMNODE pLunL0,
4935 PCFGMNODE pInst,
4936 bool fAttachDetach,
4937 bool fIgnoreConnectFailure)
4938{
4939 RT_NOREF(fIgnoreConnectFailure);
4940 AutoCaller autoCaller(this);
4941 AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED);
4942
4943 // InsertConfig* throws
4944 try
4945 {
4946 int rc = VINF_SUCCESS;
4947 HRESULT hrc;
4948 Bstr bstr;
4949
4950#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4951
4952 /*
4953 * Locking the object before doing VMR3* calls is quite safe here, since
4954 * we're on EMT. Write lock is necessary because we indirectly modify the
4955 * meAttachmentType member.
4956 */
4957 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
4958
4959 ComPtr<IMachine> pMachine = i_machine();
4960
4961 ComPtr<IVirtualBox> virtualBox;
4962 hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam()); H();
4963
4964 ComPtr<IHost> host;
4965 hrc = virtualBox->COMGETTER(Host)(host.asOutParam()); H();
4966
4967 BOOL fSniffer;
4968 hrc = aNetworkAdapter->COMGETTER(TraceEnabled)(&fSniffer); H();
4969
4970 NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy;
4971 hrc = aNetworkAdapter->COMGETTER(PromiscModePolicy)(&enmPromiscModePolicy); H();
4972 const char *pszPromiscuousGuestPolicy;
4973 switch (enmPromiscModePolicy)
4974 {
4975 case NetworkAdapterPromiscModePolicy_Deny: pszPromiscuousGuestPolicy = "deny"; break;
4976 case NetworkAdapterPromiscModePolicy_AllowNetwork: pszPromiscuousGuestPolicy = "allow-network"; break;
4977 case NetworkAdapterPromiscModePolicy_AllowAll: pszPromiscuousGuestPolicy = "allow-all"; break;
4978 default: AssertFailedReturn(VERR_INTERNAL_ERROR_4);
4979 }
4980
4981 if (fAttachDetach)
4982 {
4983 rc = PDMR3DeviceDetach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/);
4984 if (rc == VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4985 rc = VINF_SUCCESS;
4986 AssertLogRelRCReturn(rc, rc);
4987
4988 /* Nuke anything which might have been left behind. */
4989 CFGMR3RemoveNode(CFGMR3GetChildF(pInst, "LUN#%u", uLun));
4990 }
4991
4992#ifdef VBOX_WITH_NETSHAPER
4993 ComObjPtr<IBandwidthGroup> pBwGroup;
4994 Bstr strBwGroup;
4995 hrc = aNetworkAdapter->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
4996
4997 if (!pBwGroup.isNull())
4998 {
4999 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
5000 }
5001#endif /* VBOX_WITH_NETSHAPER */
5002
5003 AssertMsg(uLun == 0, ("Network attachments with LUN > 0 are not supported yet\n"));
5004 CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%u", uLun);
5005
5006#ifdef VBOX_WITH_NETSHAPER
5007 if (!strBwGroup.isEmpty())
5008 {
5009 InsertConfigString(pLunL0, "Driver", "NetShaper");
5010 InsertConfigNode(pLunL0, "Config", &pCfg);
5011 InsertConfigString(pCfg, "BwGroup", strBwGroup);
5012 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
5013 }
5014#endif /* VBOX_WITH_NETSHAPER */
5015
5016 if (fSniffer)
5017 {
5018 InsertConfigString(pLunL0, "Driver", "NetSniffer");
5019 InsertConfigNode(pLunL0, "Config", &pCfg);
5020 hrc = aNetworkAdapter->COMGETTER(TraceFile)(bstr.asOutParam()); H();
5021 if (!bstr.isEmpty()) /* check convention for indicating default file. */
5022 InsertConfigString(pCfg, "File", bstr);
5023 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
5024 }
5025
5026
5027 Bstr networkName, trunkName, trunkType;
5028 NetworkAttachmentType_T eAttachmentType;
5029 hrc = aNetworkAdapter->COMGETTER(AttachmentType)(&eAttachmentType); H();
5030 switch (eAttachmentType)
5031 {
5032 case NetworkAttachmentType_Null:
5033 break;
5034
5035 case NetworkAttachmentType_NAT:
5036 {
5037 ComPtr<INATEngine> natEngine;
5038 hrc = aNetworkAdapter->COMGETTER(NATEngine)(natEngine.asOutParam()); H();
5039 InsertConfigString(pLunL0, "Driver", "NAT");
5040 InsertConfigNode(pLunL0, "Config", &pCfg);
5041
5042 /* Configure TFTP prefix and boot filename. */
5043 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
5044 if (!bstr.isEmpty())
5045 InsertConfigString(pCfg, "TFTPPrefix", Utf8StrFmt("%ls%c%s", bstr.raw(), RTPATH_DELIMITER, "TFTP"));
5046 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
5047 InsertConfigString(pCfg, "BootFile", Utf8StrFmt("%ls.pxe", bstr.raw()));
5048
5049 hrc = natEngine->COMGETTER(Network)(bstr.asOutParam()); H();
5050 if (!bstr.isEmpty())
5051 InsertConfigString(pCfg, "Network", bstr);
5052 else
5053 {
5054 ULONG uSlot;
5055 hrc = aNetworkAdapter->COMGETTER(Slot)(&uSlot); H();
5056 InsertConfigString(pCfg, "Network", Utf8StrFmt("10.0.%d.0/24", uSlot+2));
5057 }
5058 hrc = natEngine->COMGETTER(HostIP)(bstr.asOutParam()); H();
5059 if (!bstr.isEmpty())
5060 InsertConfigString(pCfg, "BindIP", bstr);
5061 ULONG mtu = 0;
5062 ULONG sockSnd = 0;
5063 ULONG sockRcv = 0;
5064 ULONG tcpSnd = 0;
5065 ULONG tcpRcv = 0;
5066 hrc = natEngine->GetNetworkSettings(&mtu, &sockSnd, &sockRcv, &tcpSnd, &tcpRcv); H();
5067 if (mtu)
5068 InsertConfigInteger(pCfg, "SlirpMTU", mtu);
5069 if (sockRcv)
5070 InsertConfigInteger(pCfg, "SockRcv", sockRcv);
5071 if (sockSnd)
5072 InsertConfigInteger(pCfg, "SockSnd", sockSnd);
5073 if (tcpRcv)
5074 InsertConfigInteger(pCfg, "TcpRcv", tcpRcv);
5075 if (tcpSnd)
5076 InsertConfigInteger(pCfg, "TcpSnd", tcpSnd);
5077 hrc = natEngine->COMGETTER(TFTPPrefix)(bstr.asOutParam()); H();
5078 if (!bstr.isEmpty())
5079 {
5080 RemoveConfigValue(pCfg, "TFTPPrefix");
5081 InsertConfigString(pCfg, "TFTPPrefix", bstr);
5082 }
5083 hrc = natEngine->COMGETTER(TFTPBootFile)(bstr.asOutParam()); H();
5084 if (!bstr.isEmpty())
5085 {
5086 RemoveConfigValue(pCfg, "BootFile");
5087 InsertConfigString(pCfg, "BootFile", bstr);
5088 }
5089 hrc = natEngine->COMGETTER(TFTPNextServer)(bstr.asOutParam()); H();
5090 if (!bstr.isEmpty())
5091 InsertConfigString(pCfg, "NextServer", bstr);
5092 BOOL fDNSFlag;
5093 hrc = natEngine->COMGETTER(DNSPassDomain)(&fDNSFlag); H();
5094 InsertConfigInteger(pCfg, "PassDomain", fDNSFlag);
5095 hrc = natEngine->COMGETTER(DNSProxy)(&fDNSFlag); H();
5096 InsertConfigInteger(pCfg, "DNSProxy", fDNSFlag);
5097 hrc = natEngine->COMGETTER(DNSUseHostResolver)(&fDNSFlag); H();
5098 InsertConfigInteger(pCfg, "UseHostResolver", fDNSFlag);
5099
5100 ULONG aliasMode;
5101 hrc = natEngine->COMGETTER(AliasMode)(&aliasMode); H();
5102 InsertConfigInteger(pCfg, "AliasMode", aliasMode);
5103
5104 /* port-forwarding */
5105 SafeArray<BSTR> pfs;
5106 hrc = natEngine->COMGETTER(Redirects)(ComSafeArrayAsOutParam(pfs)); H();
5107
5108 PCFGMNODE pPFTree = NULL;
5109 if (pfs.size() > 0)
5110 InsertConfigNode(pCfg, "PortForwarding", &pPFTree);
5111
5112 for (unsigned int i = 0; i < pfs.size(); ++i)
5113 {
5114 PCFGMNODE pPF = NULL; /* /Devices/Dev/.../Config/PortForwarding/$n/ */
5115
5116 uint16_t port = 0;
5117 Utf8Str utf = pfs[i];
5118 Utf8Str strName;
5119 Utf8Str strProto;
5120 Utf8Str strHostPort;
5121 Utf8Str strHostIP;
5122 Utf8Str strGuestPort;
5123 Utf8Str strGuestIP;
5124 size_t pos, ppos;
5125 pos = ppos = 0;
5126#define ITERATE_TO_NEXT_TERM(res, str, pos, ppos) \
5127 { \
5128 pos = str.find(",", ppos); \
5129 if (pos == Utf8Str::npos) \
5130 { \
5131 Log(( #res " extracting from %s is failed\n", str.c_str())); \
5132 continue; \
5133 } \
5134 res = str.substr(ppos, pos - ppos); \
5135 Log2((#res " %s pos:%d, ppos:%d\n", res.c_str(), pos, ppos)); \
5136 ppos = pos + 1; \
5137 } /* no do { ... } while because of 'continue' */
5138 ITERATE_TO_NEXT_TERM(strName, utf, pos, ppos);
5139 ITERATE_TO_NEXT_TERM(strProto, utf, pos, ppos);
5140 ITERATE_TO_NEXT_TERM(strHostIP, utf, pos, ppos);
5141 ITERATE_TO_NEXT_TERM(strHostPort, utf, pos, ppos);
5142 ITERATE_TO_NEXT_TERM(strGuestIP, utf, pos, ppos);
5143 strGuestPort = utf.substr(ppos, utf.length() - ppos);
5144#undef ITERATE_TO_NEXT_TERM
5145
5146 uint32_t proto = strProto.toUInt32();
5147 bool fValid = true;
5148 switch (proto)
5149 {
5150 case NATProtocol_UDP:
5151 strProto = "UDP";
5152 break;
5153 case NATProtocol_TCP:
5154 strProto = "TCP";
5155 break;
5156 default:
5157 fValid = false;
5158 }
5159 /* continue with next rule if no valid proto was passed */
5160 if (!fValid)
5161 continue;
5162
5163 InsertConfigNode(pPFTree, Utf8StrFmt("%u", i).c_str(), &pPF);
5164
5165 if (!strName.isEmpty())
5166 InsertConfigString(pPF, "Name", strName);
5167
5168 InsertConfigString(pPF, "Protocol", strProto);
5169
5170 if (!strHostIP.isEmpty())
5171 InsertConfigString(pPF, "BindIP", strHostIP);
5172
5173 if (!strGuestIP.isEmpty())
5174 InsertConfigString(pPF, "GuestIP", strGuestIP);
5175
5176 port = RTStrToUInt16(strHostPort.c_str());
5177 if (port)
5178 InsertConfigInteger(pPF, "HostPort", port);
5179
5180 port = RTStrToUInt16(strGuestPort.c_str());
5181 if (port)
5182 InsertConfigInteger(pPF, "GuestPort", port);
5183 }
5184 break;
5185 }
5186
5187 case NetworkAttachmentType_Bridged:
5188 {
5189#if (defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)) && !defined(VBOX_WITH_NETFLT)
5190 hrc = i_attachToTapInterface(aNetworkAdapter);
5191 if (FAILED(hrc))
5192 {
5193 switch (hrc)
5194 {
5195 case VERR_ACCESS_DENIED:
5196 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5197 "Failed to open '/dev/net/tun' for read/write access. Please check the "
5198 "permissions of that node. Either run 'chmod 0666 /dev/net/tun' or "
5199 "change the group of that node and make yourself a member of that group. Make "
5200 "sure that these changes are permanent, especially if you are "
5201 "using udev"));
5202 default:
5203 AssertMsgFailed(("Could not attach to host interface! Bad!\n"));
5204 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5205 "Failed to initialize Host Interface Networking"));
5206 }
5207 }
5208
5209 Assert((intptr_t)maTapFD[uInstance] >= 0);
5210 if ((intptr_t)maTapFD[uInstance] >= 0)
5211 {
5212 InsertConfigString(pLunL0, "Driver", "HostInterface");
5213 InsertConfigNode(pLunL0, "Config", &pCfg);
5214 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
5215 }
5216
5217#elif defined(VBOX_WITH_NETFLT)
5218 /*
5219 * This is the new VBoxNetFlt+IntNet stuff.
5220 */
5221 Bstr BridgedIfName;
5222 hrc = aNetworkAdapter->COMGETTER(BridgedInterface)(BridgedIfName.asOutParam());
5223 if (FAILED(hrc))
5224 {
5225 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(BridgedInterface) failed, hrc (0x%x)\n", hrc));
5226 H();
5227 }
5228
5229 Utf8Str BridgedIfNameUtf8(BridgedIfName);
5230 const char *pszBridgedIfName = BridgedIfNameUtf8.c_str();
5231
5232 ComPtr<IHostNetworkInterface> hostInterface;
5233 hrc = host->FindHostNetworkInterfaceByName(BridgedIfName.raw(),
5234 hostInterface.asOutParam());
5235 if (!SUCCEEDED(hrc))
5236 {
5237 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: FindByName failed, rc=%Rhrc (0x%x)", hrc, hrc));
5238 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5239 N_("Nonexistent host networking interface, name '%ls'"),
5240 BridgedIfName.raw());
5241 }
5242
5243# if defined(RT_OS_DARWIN)
5244 /* The name is on the form 'ifX: long name', chop it off at the colon. */
5245 char szTrunk[INTNET_MAX_TRUNK_NAME];
5246 RTStrCopy(szTrunk, sizeof(szTrunk), pszBridgedIfName);
5247 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
5248// Quick fix for @bugref{5633}
5249// if (!pszColon)
5250// {
5251// /*
5252// * Dynamic changing of attachment causes an attempt to configure
5253// * network with invalid host adapter (as it is must be changed before
5254// * the attachment), calling Detach here will cause a deadlock.
5255// * See @bugref{4750}.
5256// * hrc = aNetworkAdapter->Detach(); H();
5257// */
5258// return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5259// N_("Malformed host interface networking name '%ls'"),
5260// BridgedIfName.raw());
5261// }
5262 if (pszColon)
5263 *pszColon = '\0';
5264 const char *pszTrunk = szTrunk;
5265
5266# elif defined(RT_OS_SOLARIS)
5267 /* The name is on the form format 'ifX[:1] - long name, chop it off at space. */
5268 char szTrunk[256];
5269 strlcpy(szTrunk, pszBridgedIfName, sizeof(szTrunk));
5270 char *pszSpace = (char *)memchr(szTrunk, ' ', sizeof(szTrunk));
5271
5272 /*
5273 * Currently don't bother about malformed names here for the sake of people using
5274 * VBoxManage and setting only the NIC name from there. If there is a space we
5275 * chop it off and proceed, otherwise just use whatever we've got.
5276 */
5277 if (pszSpace)
5278 *pszSpace = '\0';
5279
5280 /* Chop it off at the colon (zone naming eg: e1000g:1 we need only the e1000g) */
5281 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
5282 if (pszColon)
5283 *pszColon = '\0';
5284
5285 const char *pszTrunk = szTrunk;
5286
5287# elif defined(RT_OS_WINDOWS)
5288 HostNetworkInterfaceType_T eIfType;
5289 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
5290 if (FAILED(hrc))
5291 {
5292 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
5293 H();
5294 }
5295
5296 if (eIfType != HostNetworkInterfaceType_Bridged)
5297 {
5298 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5299 N_("Interface ('%ls') is not a Bridged Adapter interface"),
5300 BridgedIfName.raw());
5301 }
5302
5303 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
5304 if (FAILED(hrc))
5305 {
5306 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
5307 H();
5308 }
5309 Guid hostIFGuid(bstr);
5310
5311 INetCfg *pNc;
5312 ComPtr<INetCfgComponent> pAdaptorComponent;
5313 LPWSTR pszApp;
5314
5315 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
5316 Assert(hrc == S_OK);
5317 if (hrc != S_OK)
5318 {
5319 LogRel(("NetworkAttachmentType_Bridged: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5320 H();
5321 }
5322
5323 /* get the adapter's INetCfgComponent*/
5324 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
5325 pAdaptorComponent.asOutParam());
5326 if (hrc != S_OK)
5327 {
5328 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5329 LogRel(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)\n", hrc));
5330 H();
5331 }
5332# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
5333 char szTrunkName[INTNET_MAX_TRUNK_NAME];
5334 char *pszTrunkName = szTrunkName;
5335 wchar_t * pswzBindName;
5336 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
5337 Assert(hrc == S_OK);
5338 if (hrc == S_OK)
5339 {
5340 int cwBindName = (int)wcslen(pswzBindName) + 1;
5341 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
5342 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
5343 {
5344 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
5345 pszTrunkName += cbFullBindNamePrefix-1;
5346 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
5347 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
5348 {
5349 DWORD err = GetLastError();
5350 hrc = HRESULT_FROM_WIN32(err);
5351 AssertMsgFailed(("hrc=%Rhrc %#x\n", hrc, hrc));
5352 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
5353 hrc, hrc, err));
5354 }
5355 }
5356 else
5357 {
5358 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: insufficient szTrunkName buffer space\n"));
5359 /** @todo set appropriate error code */
5360 hrc = E_FAIL;
5361 }
5362
5363 if (hrc != S_OK)
5364 {
5365 AssertFailed();
5366 CoTaskMemFree(pswzBindName);
5367 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5368 H();
5369 }
5370
5371 /* we're not freeing the bind name since we'll use it later for detecting wireless*/
5372 }
5373 else
5374 {
5375 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5376 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)",
5377 hrc));
5378 H();
5379 }
5380
5381 const char *pszTrunk = szTrunkName;
5382 /* we're not releasing the INetCfg stuff here since we use it later to figure out whether it is wireless */
5383
5384# elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
5385# if defined(RT_OS_FREEBSD)
5386 /*
5387 * If we bridge to a tap interface open it the `old' direct way.
5388 * This works and performs better than bridging a physical
5389 * interface via the current FreeBSD vboxnetflt implementation.
5390 */
5391 if (!strncmp(pszBridgedIfName, RT_STR_TUPLE("tap"))) {
5392 hrc = i_attachToTapInterface(aNetworkAdapter);
5393 if (FAILED(hrc))
5394 {
5395 switch (hrc)
5396 {
5397 case E_ACCESSDENIED:
5398 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5399 "Failed to open '/dev/%s' for read/write access. Please check the "
5400 "permissions of that node, and that the net.link.tap.user_open "
5401 "sysctl is set. Either run 'chmod 0666 /dev/%s' or "
5402 "change the group of that node to vboxusers and make yourself "
5403 "a member of that group. Make sure that these changes are permanent."),
5404 pszBridgedIfName, pszBridgedIfName);
5405 default:
5406 AssertMsgFailed(("Could not attach to tap interface! Bad!\n"));
5407 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5408 "Failed to initialize Host Interface Networking"));
5409 }
5410 }
5411
5412 Assert((intptr_t)maTapFD[uInstance] >= 0);
5413 if ((intptr_t)maTapFD[uInstance] >= 0)
5414 {
5415 InsertConfigString(pLunL0, "Driver", "HostInterface");
5416 InsertConfigNode(pLunL0, "Config", &pCfg);
5417 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
5418 }
5419 break;
5420 }
5421# endif
5422 /** @todo Check for malformed names. */
5423 const char *pszTrunk = pszBridgedIfName;
5424
5425 /* Issue a warning if the interface is down */
5426 {
5427 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
5428 if (iSock >= 0)
5429 {
5430 struct ifreq Req;
5431 RT_ZERO(Req);
5432 RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pszBridgedIfName);
5433 if (ioctl(iSock, SIOCGIFFLAGS, &Req) >= 0)
5434 if ((Req.ifr_flags & IFF_UP) == 0)
5435 i_atVMRuntimeErrorCallbackF(0, "BridgedInterfaceDown",
5436 N_("Bridged interface %s is down. Guest will not be able to use this interface"),
5437 pszBridgedIfName);
5438
5439 close(iSock);
5440 }
5441 }
5442
5443# else
5444# error "PORTME (VBOX_WITH_NETFLT)"
5445# endif
5446
5447 InsertConfigString(pLunL0, "Driver", "IntNet");
5448 InsertConfigNode(pLunL0, "Config", &pCfg);
5449 InsertConfigString(pCfg, "Trunk", pszTrunk);
5450 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
5451 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure);
5452 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5453 char szNetwork[INTNET_MAX_NETWORK_NAME];
5454
5455# if defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN)
5456 /*
5457 * 'pszTrunk' contains just the interface name required in ring-0, while 'pszBridgedIfName' contains
5458 * interface name + optional description. We must not pass any description to the VM as it can differ
5459 * for the same interface name, eg: "nge0 - ethernet" (GUI) vs "nge0" (VBoxManage).
5460 */
5461 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszTrunk);
5462# else
5463 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszBridgedIfName);
5464# endif
5465 InsertConfigString(pCfg, "Network", szNetwork);
5466 networkName = Bstr(szNetwork);
5467 trunkName = Bstr(pszTrunk);
5468 trunkType = Bstr(TRUNKTYPE_NETFLT);
5469
5470 BOOL fSharedMacOnWire = false;
5471 hrc = hostInterface->COMGETTER(Wireless)(&fSharedMacOnWire);
5472 if (FAILED(hrc))
5473 {
5474 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Wireless) failed, hrc (0x%x)\n", hrc));
5475 H();
5476 }
5477 else if (fSharedMacOnWire)
5478 {
5479 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5480 Log(("Set SharedMacOnWire\n"));
5481 }
5482
5483# if defined(RT_OS_SOLARIS)
5484# if 0 /* bird: this is a bit questionable and might cause more trouble than its worth. */
5485 /* Zone access restriction, don't allow snooping the global zone. */
5486 zoneid_t ZoneId = getzoneid();
5487 if (ZoneId != GLOBAL_ZONEID)
5488 {
5489 InsertConfigInteger(pCfg, "IgnoreAllPromisc", true);
5490 }
5491# endif
5492# endif
5493
5494#elif defined(RT_OS_WINDOWS) /* not defined NetFlt */
5495 /* NOTHING TO DO HERE */
5496#elif defined(RT_OS_LINUX)
5497/// @todo aleksey: is there anything to be done here?
5498#elif defined(RT_OS_FREEBSD)
5499/** @todo FreeBSD: Check out this later (HIF networking). */
5500#else
5501# error "Port me"
5502#endif
5503 break;
5504 }
5505
5506 case NetworkAttachmentType_Internal:
5507 {
5508 hrc = aNetworkAdapter->COMGETTER(InternalNetwork)(bstr.asOutParam()); H();
5509 if (!bstr.isEmpty())
5510 {
5511 InsertConfigString(pLunL0, "Driver", "IntNet");
5512 InsertConfigNode(pLunL0, "Config", &pCfg);
5513 InsertConfigString(pCfg, "Network", bstr);
5514 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
5515 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5516 networkName = bstr;
5517 trunkType = Bstr(TRUNKTYPE_WHATEVER);
5518 }
5519 break;
5520 }
5521
5522 case NetworkAttachmentType_HostOnly:
5523 {
5524 InsertConfigString(pLunL0, "Driver", "IntNet");
5525 InsertConfigNode(pLunL0, "Config", &pCfg);
5526
5527 Bstr HostOnlyName;
5528 hrc = aNetworkAdapter->COMGETTER(HostOnlyInterface)(HostOnlyName.asOutParam());
5529 if (FAILED(hrc))
5530 {
5531 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(HostOnlyInterface) failed, hrc (0x%x)\n", hrc));
5532 H();
5533 }
5534
5535 Utf8Str HostOnlyNameUtf8(HostOnlyName);
5536 const char *pszHostOnlyName = HostOnlyNameUtf8.c_str();
5537 ComPtr<IHostNetworkInterface> hostInterface;
5538 rc = host->FindHostNetworkInterfaceByName(HostOnlyName.raw(),
5539 hostInterface.asOutParam());
5540 if (!SUCCEEDED(rc))
5541 {
5542 LogRel(("NetworkAttachmentType_HostOnly: FindByName failed, rc (0x%x)\n", rc));
5543 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5544 N_("Nonexistent host networking interface, name '%ls'"),
5545 HostOnlyName.raw());
5546 }
5547
5548 char szNetwork[INTNET_MAX_NETWORK_NAME];
5549 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszHostOnlyName);
5550
5551#if defined(RT_OS_WINDOWS)
5552# ifndef VBOX_WITH_NETFLT
5553 hrc = E_NOTIMPL;
5554 LogRel(("NetworkAttachmentType_HostOnly: Not Implemented\n"));
5555 H();
5556# else /* defined VBOX_WITH_NETFLT*/
5557 /** @todo r=bird: Put this in a function. */
5558
5559 HostNetworkInterfaceType_T eIfType;
5560 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
5561 if (FAILED(hrc))
5562 {
5563 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
5564 H();
5565 }
5566
5567 if (eIfType != HostNetworkInterfaceType_HostOnly)
5568 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5569 N_("Interface ('%ls') is not a Host-Only Adapter interface"),
5570 HostOnlyName.raw());
5571
5572 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
5573 if (FAILED(hrc))
5574 {
5575 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
5576 H();
5577 }
5578 Guid hostIFGuid(bstr);
5579
5580 INetCfg *pNc;
5581 ComPtr<INetCfgComponent> pAdaptorComponent;
5582 LPWSTR pszApp;
5583 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
5584 Assert(hrc == S_OK);
5585 if (hrc != S_OK)
5586 {
5587 LogRel(("NetworkAttachmentType_HostOnly: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5588 H();
5589 }
5590
5591 /* get the adapter's INetCfgComponent*/
5592 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
5593 pAdaptorComponent.asOutParam());
5594 if (hrc != S_OK)
5595 {
5596 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5597 LogRel(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5598 H();
5599 }
5600# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
5601 char szTrunkName[INTNET_MAX_TRUNK_NAME];
5602 bool fNdis6 = false;
5603 wchar_t * pwszHelpText;
5604 hrc = pAdaptorComponent->GetHelpText(&pwszHelpText);
5605 Assert(hrc == S_OK);
5606 if (hrc == S_OK)
5607 {
5608 Log(("help-text=%ls\n", pwszHelpText));
5609 if (!wcscmp(pwszHelpText, L"VirtualBox NDIS 6.0 Miniport Driver"))
5610 fNdis6 = true;
5611 CoTaskMemFree(pwszHelpText);
5612 }
5613 if (fNdis6)
5614 {
5615 strncpy(szTrunkName, pszHostOnlyName, sizeof(szTrunkName) - 1);
5616 Log(("trunk=%s\n", szTrunkName));
5617 }
5618 else
5619 {
5620 char *pszTrunkName = szTrunkName;
5621 wchar_t * pswzBindName;
5622 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
5623 Assert(hrc == S_OK);
5624 if (hrc == S_OK)
5625 {
5626 int cwBindName = (int)wcslen(pswzBindName) + 1;
5627 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
5628 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
5629 {
5630 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
5631 pszTrunkName += cbFullBindNamePrefix-1;
5632 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
5633 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
5634 {
5635 DWORD err = GetLastError();
5636 hrc = HRESULT_FROM_WIN32(err);
5637 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
5638 hrc, hrc, err));
5639 }
5640 }
5641 else
5642 {
5643 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: insufficient szTrunkName buffer space\n"));
5644 /** @todo set appropriate error code */
5645 hrc = E_FAIL;
5646 }
5647
5648 if (hrc != S_OK)
5649 {
5650 AssertFailed();
5651 CoTaskMemFree(pswzBindName);
5652 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5653 H();
5654 }
5655 }
5656 else
5657 {
5658 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5659 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n",
5660 hrc, hrc));
5661 H();
5662 }
5663
5664
5665 CoTaskMemFree(pswzBindName);
5666 }
5667
5668 trunkType = TRUNKTYPE_NETADP;
5669 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
5670
5671 pAdaptorComponent.setNull();
5672 /* release the pNc finally */
5673 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5674
5675 const char *pszTrunk = szTrunkName;
5676
5677 InsertConfigString(pCfg, "Trunk", pszTrunk);
5678 InsertConfigString(pCfg, "Network", szNetwork);
5679 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure); /** @todo why is this
5680 windows only?? */
5681 networkName = Bstr(szNetwork);
5682 trunkName = Bstr(pszTrunk);
5683# endif /* defined VBOX_WITH_NETFLT*/
5684#elif defined(RT_OS_DARWIN)
5685 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
5686 InsertConfigString(pCfg, "Network", szNetwork);
5687 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
5688 networkName = Bstr(szNetwork);
5689 trunkName = Bstr(pszHostOnlyName);
5690 trunkType = TRUNKTYPE_NETADP;
5691#else
5692 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
5693 InsertConfigString(pCfg, "Network", szNetwork);
5694 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
5695 networkName = Bstr(szNetwork);
5696 trunkName = Bstr(pszHostOnlyName);
5697 trunkType = TRUNKTYPE_NETFLT;
5698#endif
5699 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5700
5701#if !defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
5702
5703 Bstr tmpAddr, tmpMask;
5704
5705 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPAddress",
5706 pszHostOnlyName).raw(),
5707 tmpAddr.asOutParam());
5708 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty())
5709 {
5710 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPNetMask",
5711 pszHostOnlyName).raw(),
5712 tmpMask.asOutParam());
5713 if (SUCCEEDED(hrc) && !tmpMask.isEmpty())
5714 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
5715 tmpMask.raw());
5716 else
5717 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
5718 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
5719 }
5720 else
5721 {
5722 /* Grab the IP number from the 'vboxnetX' instance number (see netif.h) */
5723 hrc = hostInterface->EnableStaticIPConfig(getDefaultIPv4Address(Bstr(pszHostOnlyName)).raw(),
5724 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
5725 }
5726
5727 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
5728
5729 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6Address",
5730 pszHostOnlyName).raw(),
5731 tmpAddr.asOutParam());
5732 if (SUCCEEDED(hrc))
5733 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6NetMask", pszHostOnlyName).raw(),
5734 tmpMask.asOutParam());
5735 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty() && !tmpMask.isEmpty())
5736 {
5737 hrc = hostInterface->EnableStaticIPConfigV6(tmpAddr.raw(),
5738 Utf8Str(tmpMask).toUInt32());
5739 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
5740 }
5741#endif
5742 break;
5743 }
5744
5745 case NetworkAttachmentType_Generic:
5746 {
5747 hrc = aNetworkAdapter->COMGETTER(GenericDriver)(bstr.asOutParam()); H();
5748 SafeArray<BSTR> names;
5749 SafeArray<BSTR> values;
5750 hrc = aNetworkAdapter->GetProperties(Bstr().raw(),
5751 ComSafeArrayAsOutParam(names),
5752 ComSafeArrayAsOutParam(values)); H();
5753
5754 InsertConfigString(pLunL0, "Driver", bstr);
5755 InsertConfigNode(pLunL0, "Config", &pCfg);
5756 for (size_t ii = 0; ii < names.size(); ++ii)
5757 {
5758 if (values[ii] && *values[ii])
5759 {
5760 Utf8Str name = names[ii];
5761 Utf8Str value = values[ii];
5762 InsertConfigString(pCfg, name.c_str(), value);
5763 }
5764 }
5765 break;
5766 }
5767
5768 case NetworkAttachmentType_NATNetwork:
5769 {
5770 hrc = aNetworkAdapter->COMGETTER(NATNetwork)(bstr.asOutParam()); H();
5771 if (!bstr.isEmpty())
5772 {
5773 /** @todo add intnet prefix to separate namespaces, and add trunk if dealing with vboxnatX */
5774 InsertConfigString(pLunL0, "Driver", "IntNet");
5775 InsertConfigNode(pLunL0, "Config", &pCfg);
5776 InsertConfigString(pCfg, "Network", bstr);
5777 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
5778 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5779 networkName = bstr;
5780 trunkType = Bstr(TRUNKTYPE_WHATEVER);
5781 }
5782 break;
5783 }
5784
5785 default:
5786 AssertMsgFailed(("should not get here!\n"));
5787 break;
5788 }
5789
5790 /*
5791 * Attempt to attach the driver.
5792 */
5793 switch (eAttachmentType)
5794 {
5795 case NetworkAttachmentType_Null:
5796 break;
5797
5798 case NetworkAttachmentType_Bridged:
5799 case NetworkAttachmentType_Internal:
5800 case NetworkAttachmentType_HostOnly:
5801 case NetworkAttachmentType_NAT:
5802 case NetworkAttachmentType_Generic:
5803 case NetworkAttachmentType_NATNetwork:
5804 {
5805 if (SUCCEEDED(hrc) && RT_SUCCESS(rc))
5806 {
5807 if (fAttachDetach)
5808 {
5809 rc = PDMR3DriverAttach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/, NULL /* ppBase */);
5810 //AssertRC(rc);
5811 }
5812
5813 {
5814 /** @todo pritesh: get the dhcp server name from the
5815 * previous network configuration and then stop the server
5816 * else it may conflict with the dhcp server running with
5817 * the current attachment type
5818 */
5819 /* Stop the hostonly DHCP Server */
5820 }
5821
5822 /*
5823 * NAT networks start their DHCP server theirself, see NATNetwork::Start()
5824 */
5825 if ( !networkName.isEmpty()
5826 && eAttachmentType != NetworkAttachmentType_NATNetwork)
5827 {
5828 /*
5829 * Until we implement service reference counters DHCP Server will be stopped
5830 * by DHCPServerRunner destructor.
5831 */
5832 ComPtr<IDHCPServer> dhcpServer;
5833 hrc = virtualBox->FindDHCPServerByNetworkName(networkName.raw(),
5834 dhcpServer.asOutParam());
5835 if (SUCCEEDED(hrc))
5836 {
5837 /* there is a DHCP server available for this network */
5838 BOOL fEnabledDhcp;
5839 hrc = dhcpServer->COMGETTER(Enabled)(&fEnabledDhcp);
5840 if (FAILED(hrc))
5841 {
5842 LogRel(("DHCP svr: COMGETTER(Enabled) failed, hrc (%Rhrc)\n", hrc));
5843 H();
5844 }
5845
5846 if (fEnabledDhcp)
5847 hrc = dhcpServer->Start(networkName.raw(),
5848 trunkName.raw(),
5849 trunkType.raw());
5850 }
5851 else
5852 hrc = S_OK;
5853 }
5854 }
5855
5856 break;
5857 }
5858
5859 default:
5860 AssertMsgFailed(("should not get here!\n"));
5861 break;
5862 }
5863
5864 meAttachmentType[uInstance] = eAttachmentType;
5865 }
5866 catch (ConfigError &x)
5867 {
5868 // InsertConfig threw something:
5869 return x.m_vrc;
5870 }
5871
5872#undef H
5873
5874 return VINF_SUCCESS;
5875}
5876
5877
5878/**
5879 * Configures the serial port at the given CFGM node with the supplied parameters.
5880 *
5881 * @returns VBox status code.
5882 * @param pInst The instance CFGM node.
5883 * @param ePortMode The port mode to sue.
5884 * @param pszPath The serial port path.
5885 * @param fServer Flag whether the port should act as a server
5886 * for the pipe and TCP mode or connect as a client.
5887 */
5888int Console::i_configSerialPort(PCFGMNODE pInst, PortMode_T ePortMode, const char *pszPath, bool fServer)
5889{
5890 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
5891 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */
5892 PCFGMNODE pLunL1Cfg = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/Config */
5893
5894 try
5895 {
5896 InsertConfigNode(pInst, "LUN#0", &pLunL0);
5897 if (ePortMode == PortMode_HostPipe)
5898 {
5899 InsertConfigString(pLunL0, "Driver", "Char");
5900 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
5901 InsertConfigString(pLunL1, "Driver", "NamedPipe");
5902 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
5903 InsertConfigString(pLunL1Cfg, "Location", pszPath);
5904 InsertConfigInteger(pLunL1Cfg, "IsServer", fServer);
5905 }
5906 else if (ePortMode == PortMode_HostDevice)
5907 {
5908 InsertConfigString(pLunL0, "Driver", "Host Serial");
5909 InsertConfigNode(pLunL0, "Config", &pLunL1);
5910 InsertConfigString(pLunL1, "DevicePath", pszPath);
5911 }
5912 else if (ePortMode == PortMode_TCP)
5913 {
5914 InsertConfigString(pLunL0, "Driver", "Char");
5915 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
5916 InsertConfigString(pLunL1, "Driver", "TCP");
5917 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
5918 InsertConfigString(pLunL1Cfg, "Location", pszPath);
5919 InsertConfigInteger(pLunL1Cfg, "IsServer", fServer);
5920 }
5921 else if (ePortMode == PortMode_RawFile)
5922 {
5923 InsertConfigString(pLunL0, "Driver", "Char");
5924 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
5925 InsertConfigString(pLunL1, "Driver", "RawFile");
5926 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
5927 InsertConfigString(pLunL1Cfg, "Location", pszPath);
5928 }
5929 }
5930 catch (ConfigError &x)
5931 {
5932 /* InsertConfig threw something */
5933 return x.m_vrc;
5934 }
5935
5936 return VINF_SUCCESS;
5937}
5938
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