VirtualBox

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

Last change on this file since 85830 was 85830, checked in by vboxsync, 4 years ago

AMD IOMMU: bugref:9654 Main/API: Enable and configure an IOMMU device when compilng with VBOX_WITH_IOMMU_AMD and ICH9 is the chipset of the VM.
Stopgap solution for until Main/API support is added for IOMMU.

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

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