VirtualBox

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

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

Audio/Main: Made the device emulation's timer rate configurable via extra data "VBoxInternal2/Audio/Device/TimerHz" (optional). ticketoem2ref:36

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