VirtualBox

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

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

Main: Added PCnet-ISA/NE2100/Am79C960 to the API (the device side is long in place).

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

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