VirtualBox

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

最後變更 在這個檔案從93015是 92996,由 vboxsync 提交於 3 年 前

virtio-net works on linux in local testing, and virtio-scsi works on windows. Integrating the switchover to make DevVirtioNet_1_0.cpp the 'virtio-net' option in the Virtual Network Controller list.

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

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