VirtualBox

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

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

Shared Clipboard/Transfers: Apply file transfers mode on VM start in Main.

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