VirtualBox

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

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

DrvAudio,ConsoleImpl2: Constructor cleanup, moved the input/output config and added range checks to it. bugref:9890

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

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