VirtualBox

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

Last change on this file since 98273 was 98268, checked in by vboxsync, 23 months ago

Main/ConsoleImpl2.cpp: rc -> hrc/vrc. bugref:10223

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 297.8 KB
Line 
1/* $Id: ConsoleImpl2.cpp 98268 2023-01-24 09:47:59Z 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-2023 Oracle and/or its affiliates.
13 *
14 * This file is part of VirtualBox base platform packages, as
15 * available from https://www.virtualbox.org.
16 *
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License
19 * as published by the Free Software Foundation, in version 3 of the
20 * License.
21 *
22 * This program is distributed in the hope that it will be useful, but
23 * WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, see <https://www.gnu.org/licenses>.
29 *
30 * SPDX-License-Identifier: GPL-3.0-only
31 */
32
33
34/*********************************************************************************************************************************
35* Header Files *
36*********************************************************************************************************************************/
37#define LOG_GROUP LOG_GROUP_MAIN_CONSOLE
38#include "LoggingNew.h"
39
40// VBoxNetCfg-win.h needs winsock2.h and thus MUST be included before any other
41// header file includes Windows.h.
42#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
43# include <VBox/VBoxNetCfg-win.h>
44#endif
45
46#include "ConsoleImpl.h"
47#include "DisplayImpl.h"
48#include "NvramStoreImpl.h"
49#ifdef VBOX_WITH_DRAG_AND_DROP
50# include "GuestImpl.h"
51# include "GuestDnDPrivate.h"
52#endif
53#include "VMMDev.h"
54#include "Global.h"
55#ifdef VBOX_WITH_PCI_PASSTHROUGH
56# include "PCIRawDevImpl.h"
57#endif
58
59// generated header
60#include "SchemaDefs.h"
61
62#include "AutoCaller.h"
63
64#include <iprt/base64.h>
65#include <iprt/buildconfig.h>
66#include <iprt/ctype.h>
67#include <iprt/dir.h>
68#include <iprt/file.h>
69#include <iprt/param.h>
70#include <iprt/path.h>
71#include <iprt/string.h>
72#include <iprt/system.h>
73#include <iprt/cpp/exception.h>
74#if 0 /* enable to play with lots of memory. */
75# include <iprt/env.h>
76#endif
77#include <iprt/stream.h>
78
79#include <iprt/http.h>
80#include <iprt/socket.h>
81#include <iprt/uri.h>
82
83#include <VBox/vmm/vmmr3vtable.h>
84#include <VBox/vmm/vmapi.h>
85#include <VBox/err.h>
86#include <VBox/param.h>
87#include <VBox/settings.h> /* For MachineConfigFile::getHostDefaultAudioDriver(). */
88#include <VBox/vmm/pdmapi.h> /* For PDMR3DriverAttach/PDMR3DriverDetach. */
89#include <VBox/vmm/pdmusb.h> /* For PDMR3UsbCreateEmulatedDevice. */
90#include <VBox/vmm/pdmdev.h> /* For PDMAPICMODE enum. */
91#include <VBox/vmm/pdmstorageifs.h>
92#include <VBox/vmm/gcm.h>
93#include <VBox/version.h>
94#ifdef VBOX_WITH_SHARED_CLIPBOARD
95# include <VBox/HostServices/VBoxClipboardSvc.h>
96#endif
97#ifdef VBOX_WITH_GUEST_PROPS
98# include <VBox/HostServices/GuestPropertySvc.h>
99# include <VBox/com/defs.h>
100# include <VBox/com/array.h>
101# include <vector>
102#endif /* VBOX_WITH_GUEST_PROPS */
103#include <VBox/intnet.h>
104
105#include <VBox/com/com.h>
106#include <VBox/com/string.h>
107#include <VBox/com/array.h>
108
109#ifdef VBOX_WITH_NETFLT
110# if defined(RT_OS_SOLARIS)
111# include <zone.h>
112# elif defined(RT_OS_LINUX)
113# include <unistd.h>
114# include <sys/ioctl.h>
115# include <sys/socket.h>
116# include <linux/types.h>
117# include <linux/if.h>
118# elif defined(RT_OS_FREEBSD)
119# include <unistd.h>
120# include <sys/types.h>
121# include <sys/ioctl.h>
122# include <sys/socket.h>
123# include <net/if.h>
124# include <net80211/ieee80211_ioctl.h>
125# endif
126# if defined(RT_OS_WINDOWS)
127# include <iprt/win/ntddndis.h>
128# include <devguid.h>
129# else
130# include <HostNetworkInterfaceImpl.h>
131# include <netif.h>
132# include <stdlib.h>
133# endif
134#endif /* VBOX_WITH_NETFLT */
135
136#ifdef VBOX_WITH_AUDIO_VRDE
137# include "DrvAudioVRDE.h"
138#endif
139#ifdef VBOX_WITH_AUDIO_RECORDING
140# include "DrvAudioRec.h"
141#endif
142#include "NetworkServiceRunner.h"
143#include "BusAssignmentManager.h"
144#ifdef VBOX_WITH_EXTPACK
145# include "ExtPackManagerImpl.h"
146#endif
147
148
149/*********************************************************************************************************************************
150* Internal Functions *
151*********************************************************************************************************************************/
152static Utf8Str *GetExtraDataBoth(IVirtualBox *pVirtualBox, IMachine *pMachine, const char *pszName, Utf8Str *pStrValue);
153
154
155/* Darwin compile kludge */
156#undef PVM
157
158/* Comment out the following line to remove VMWare compatibility hack. */
159#define VMWARE_NET_IN_SLOT_11
160
161/**
162 * Translate IDE StorageControllerType_T to string representation.
163 */
164static const char* controllerString(StorageControllerType_T enmType)
165{
166 switch (enmType)
167 {
168 case StorageControllerType_PIIX3:
169 return "PIIX3";
170 case StorageControllerType_PIIX4:
171 return "PIIX4";
172 case StorageControllerType_ICH6:
173 return "ICH6";
174 default:
175 return "Unknown";
176 }
177}
178
179/**
180 * Simple class for storing network boot information.
181 */
182struct BootNic
183{
184 ULONG mInstance;
185 PCIBusAddress mPCIAddress;
186
187 ULONG mBootPrio;
188 bool operator < (const BootNic &rhs) const
189 {
190 ULONG lval = mBootPrio - 1; /* 0 will wrap around and get the lowest priority. */
191 ULONG rval = rhs.mBootPrio - 1;
192 return lval < rval; /* Zero compares as highest number (lowest prio). */
193 }
194};
195
196#ifndef VBOX_WITH_EFI_IN_DD2
197static int findEfiRom(IVirtualBox* vbox, FirmwareType_T aFirmwareType, Utf8Str *pEfiRomFile)
198{
199 Bstr aFilePath, empty;
200 BOOL fPresent = FALSE;
201 HRESULT hrc = vbox->CheckFirmwarePresent(aFirmwareType, empty.raw(),
202 empty.asOutParam(), aFilePath.asOutParam(), &fPresent);
203 AssertComRCReturn(hrc, Global::vboxStatusCodeFromCOM(hrc));
204
205 if (!fPresent)
206 {
207 LogRel(("Failed to find an EFI ROM file.\n"));
208 return VERR_FILE_NOT_FOUND;
209 }
210
211 *pEfiRomFile = Utf8Str(aFilePath);
212
213 return VINF_SUCCESS;
214}
215#endif
216
217/**
218 * @throws HRESULT on extra data retrival error.
219 */
220static int getSmcDeviceKey(IVirtualBox *pVirtualBox, IMachine *pMachine, Utf8Str *pStrKey, bool *pfGetKeyFromRealSMC)
221{
222 *pfGetKeyFromRealSMC = false;
223
224 /*
225 * The extra data takes precedence (if non-zero).
226 */
227 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/SmcDeviceKey", pStrKey);
228 if (pStrKey->isNotEmpty())
229 return VINF_SUCCESS;
230
231#ifdef RT_OS_DARWIN
232
233 /*
234 * Work done in EFI/DevSmc
235 */
236 *pfGetKeyFromRealSMC = true;
237 int vrc = VINF_SUCCESS;
238
239#else
240 /*
241 * Is it apple hardware in bootcamp?
242 */
243 /** @todo implement + test RTSYSDMISTR_MANUFACTURER on all hosts.
244 * Currently falling back on the product name. */
245 char szManufacturer[256];
246 szManufacturer[0] = '\0';
247 RTSystemQueryDmiString(RTSYSDMISTR_MANUFACTURER, szManufacturer, sizeof(szManufacturer));
248 if (szManufacturer[0] != '\0')
249 {
250 if ( !strcmp(szManufacturer, "Apple Computer, Inc.")
251 || !strcmp(szManufacturer, "Apple Inc.")
252 )
253 *pfGetKeyFromRealSMC = true;
254 }
255 else
256 {
257 char szProdName[256];
258 szProdName[0] = '\0';
259 RTSystemQueryDmiString(RTSYSDMISTR_PRODUCT_NAME, szProdName, sizeof(szProdName));
260 if ( ( !strncmp(szProdName, RT_STR_TUPLE("Mac"))
261 || !strncmp(szProdName, RT_STR_TUPLE("iMac"))
262 || !strncmp(szProdName, RT_STR_TUPLE("Xserve"))
263 )
264 && !strchr(szProdName, ' ') /* no spaces */
265 && RT_C_IS_DIGIT(szProdName[strlen(szProdName) - 1]) /* version number */
266 )
267 *pfGetKeyFromRealSMC = true;
268 }
269
270 int vrc = VINF_SUCCESS;
271#endif
272
273 return vrc;
274}
275
276
277/*
278 * VC++ 8 / amd64 has some serious trouble with the next functions.
279 * As a temporary measure, we'll drop global optimizations.
280 */
281#if defined(_MSC_VER) && defined(RT_ARCH_AMD64)
282# if _MSC_VER >= RT_MSC_VER_VC80 && _MSC_VER < RT_MSC_VER_VC100
283# pragma optimize("g", off)
284# endif
285#endif
286
287class ConfigError : public RTCError
288{
289public:
290
291 ConfigError(const char *pcszFunction,
292 int vrc,
293 const char *pcszName)
294 : RTCError(Utf8StrFmt(Console::tr("%s failed: vrc=%Rrc, pcszName=%s"), pcszFunction, vrc, pcszName)),
295 m_vrc(vrc)
296 {
297 AssertMsgFailed(("%s\n", what())); // in strict mode, hit a breakpoint here
298 }
299
300 int m_vrc;
301};
302
303
304/**
305 * Helper that calls CFGMR3InsertString and throws an RTCError if that
306 * fails (C-string variant).
307 * @param pNode See CFGMR3InsertString.
308 * @param pcszName See CFGMR3InsertString.
309 * @param pcszValue The string value.
310 */
311void Console::InsertConfigString(PCFGMNODE pNode, const char *pcszName, const char *pcszValue)
312{
313 int vrc = mpVMM->pfnCFGMR3InsertString(pNode, pcszName, pcszValue);
314 if (RT_FAILURE(vrc))
315 throw ConfigError("CFGMR3InsertString", vrc, pcszName);
316}
317
318/**
319 * Helper that calls CFGMR3InsertString and throws an RTCError if that
320 * fails (Utf8Str variant).
321 * @param pNode See CFGMR3InsertStringN.
322 * @param pcszName See CFGMR3InsertStringN.
323 * @param rStrValue The string value.
324 */
325void Console::InsertConfigString(PCFGMNODE pNode, const char *pcszName, const Utf8Str &rStrValue)
326{
327 int vrc = mpVMM->pfnCFGMR3InsertStringN(pNode, pcszName, rStrValue.c_str(), rStrValue.length());
328 if (RT_FAILURE(vrc))
329 throw ConfigError("CFGMR3InsertStringLengthKnown", vrc, pcszName);
330}
331
332/**
333 * Helper that calls CFGMR3InsertString and throws an RTCError if that
334 * fails (Bstr variant).
335 *
336 * @param pNode See CFGMR3InsertStringN.
337 * @param pcszName See CFGMR3InsertStringN.
338 * @param rBstrValue The string value.
339 */
340void Console::InsertConfigString(PCFGMNODE pNode, const char *pcszName, const Bstr &rBstrValue)
341{
342 InsertConfigString(pNode, pcszName, Utf8Str(rBstrValue));
343}
344
345/**
346 * Helper that calls CFGMR3InsertStringFV and throws an RTCError if that fails.
347 * @param pNode See CFGMR3InsertStringF.
348 * @param pcszName See CFGMR3InsertStringF.
349 * @param pszFormat See CFGMR3InsertStringF.
350 * @param ... See CFGMR3InsertStringF.
351 */
352void Console::InsertConfigStringF(PCFGMNODE pNode, const char *pcszName, const char *pszFormat, ...)
353{
354 va_list va;
355 va_start(va, pszFormat);
356 int vrc = mpVMM->pfnCFGMR3InsertStringFV(pNode, pcszName, pszFormat, va);
357 va_end(va);
358 if (RT_FAILURE(vrc))
359 throw ConfigError("CFGMR3InsertStringFV", vrc, pcszName);
360}
361
362
363/**
364 * Helper that calls CFGMR3InsertPassword and throws an RTCError if that
365 * fails (Utf8Str variant).
366 * @param pNode See CFGMR3InsertPasswordN.
367 * @param pcszName See CFGMR3InsertPasswordN.
368 * @param rStrValue The string value.
369 */
370void Console::InsertConfigPassword(PCFGMNODE pNode, const char *pcszName, const Utf8Str &rStrValue)
371{
372 int vrc = mpVMM->pfnCFGMR3InsertPasswordN(pNode, pcszName, rStrValue.c_str(), rStrValue.length());
373 if (RT_FAILURE(vrc))
374 throw ConfigError("CFGMR3InsertPasswordLengthKnown", vrc, pcszName);
375}
376
377/**
378 * Helper that calls CFGMR3InsertBytes and throws an RTCError if that fails.
379 *
380 * @param pNode See CFGMR3InsertBytes.
381 * @param pcszName See CFGMR3InsertBytes.
382 * @param pvBytes See CFGMR3InsertBytes.
383 * @param cbBytes See CFGMR3InsertBytes.
384 */
385void Console::InsertConfigBytes(PCFGMNODE pNode, const char *pcszName, const void *pvBytes, size_t cbBytes)
386{
387 int vrc = mpVMM->pfnCFGMR3InsertBytes(pNode, pcszName, pvBytes, cbBytes);
388 if (RT_FAILURE(vrc))
389 throw ConfigError("CFGMR3InsertBytes", vrc, pcszName);
390}
391
392/**
393 * Helper that calls CFGMR3InsertInteger and throws an RTCError if that
394 * fails.
395 *
396 * @param pNode See CFGMR3InsertInteger.
397 * @param pcszName See CFGMR3InsertInteger.
398 * @param u64Integer See CFGMR3InsertInteger.
399 */
400void Console::InsertConfigInteger(PCFGMNODE pNode, const char *pcszName, uint64_t u64Integer)
401{
402 int vrc = mpVMM->pfnCFGMR3InsertInteger(pNode, pcszName, u64Integer);
403 if (RT_FAILURE(vrc))
404 throw ConfigError("CFGMR3InsertInteger", vrc, pcszName);
405}
406
407/**
408 * Helper that calls CFGMR3InsertNode and throws an RTCError if that fails.
409 *
410 * @param pNode See CFGMR3InsertNode.
411 * @param pcszName See CFGMR3InsertNode.
412 * @param ppChild See CFGMR3InsertNode.
413 */
414void Console::InsertConfigNode(PCFGMNODE pNode, const char *pcszName, PCFGMNODE *ppChild)
415{
416 int vrc = mpVMM->pfnCFGMR3InsertNode(pNode, pcszName, ppChild);
417 if (RT_FAILURE(vrc))
418 throw ConfigError("CFGMR3InsertNode", vrc, pcszName);
419}
420
421/**
422 * Helper that calls CFGMR3InsertNodeF and throws an RTCError if that fails.
423 *
424 * @param pNode See CFGMR3InsertNodeF.
425 * @param ppChild See CFGMR3InsertNodeF.
426 * @param pszNameFormat Name format string, see CFGMR3InsertNodeF.
427 * @param ... Format arguments.
428 */
429void Console::InsertConfigNodeF(PCFGMNODE pNode, PCFGMNODE *ppChild, const char *pszNameFormat, ...)
430{
431 va_list va;
432 va_start(va, pszNameFormat);
433 int vrc = mpVMM->pfnCFGMR3InsertNodeF(pNode, ppChild, "%N", pszNameFormat, &va);
434 va_end(va);
435 if (RT_FAILURE(vrc))
436 throw ConfigError("CFGMR3InsertNodeF", vrc, pszNameFormat);
437}
438
439/**
440 * Helper that calls CFGMR3RemoveValue and throws an RTCError if that fails.
441 *
442 * @param pNode See CFGMR3RemoveValue.
443 * @param pcszName See CFGMR3RemoveValue.
444 */
445void Console::RemoveConfigValue(PCFGMNODE pNode, const char *pcszName)
446{
447 int vrc = mpVMM->pfnCFGMR3RemoveValue(pNode, pcszName);
448 if (RT_FAILURE(vrc))
449 throw ConfigError("CFGMR3RemoveValue", vrc, pcszName);
450}
451
452/**
453 * Gets an extra data value, consulting both machine and global extra data.
454 *
455 * @throws HRESULT on failure
456 * @returns pStrValue for the callers convenience.
457 * @param pVirtualBox Pointer to the IVirtualBox interface.
458 * @param pMachine Pointer to the IMachine interface.
459 * @param pszName The value to get.
460 * @param pStrValue Where to return it's value (empty string if not
461 * found).
462 */
463static Utf8Str *GetExtraDataBoth(IVirtualBox *pVirtualBox, IMachine *pMachine, const char *pszName, Utf8Str *pStrValue)
464{
465 pStrValue->setNull();
466
467 Bstr bstrName(pszName);
468 Bstr bstrValue;
469 HRESULT hrc = pMachine->GetExtraData(bstrName.raw(), bstrValue.asOutParam());
470 if (FAILED(hrc))
471 throw hrc;
472 if (bstrValue.isEmpty())
473 {
474 hrc = pVirtualBox->GetExtraData(bstrName.raw(), bstrValue.asOutParam());
475 if (FAILED(hrc))
476 throw hrc;
477 }
478
479 if (bstrValue.isNotEmpty())
480 *pStrValue = bstrValue;
481 return pStrValue;
482}
483
484
485/** Helper that finds out the next HBA port used
486 */
487static LONG GetNextUsedPort(LONG aPortUsed[30], LONG lBaseVal, uint32_t u32Size)
488{
489 LONG lNextPortUsed = 30;
490 for (size_t j = 0; j < u32Size; ++j)
491 {
492 if ( aPortUsed[j] > lBaseVal
493 && aPortUsed[j] <= lNextPortUsed)
494 lNextPortUsed = aPortUsed[j];
495 }
496 return lNextPortUsed;
497}
498
499#define MAX_BIOS_LUN_COUNT 4
500
501int Console::SetBiosDiskInfo(ComPtr<IMachine> pMachine, PCFGMNODE pCfg, PCFGMNODE pBiosCfg,
502 Bstr controllerName, const char * const s_apszBiosConfig[4])
503{
504 RT_NOREF(pCfg);
505 HRESULT hrc;
506#define MAX_DEVICES 30
507#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
508
509 LONG lPortLUN[MAX_BIOS_LUN_COUNT];
510 LONG lPortUsed[MAX_DEVICES];
511 uint32_t u32HDCount = 0;
512
513 /* init to max value */
514 lPortLUN[0] = MAX_DEVICES;
515
516 com::SafeIfaceArray<IMediumAttachment> atts;
517 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),
518 ComSafeArrayAsOutParam(atts)); H();
519 size_t uNumAttachments = atts.size();
520 if (uNumAttachments > MAX_DEVICES)
521 {
522 LogRel(("Number of Attachments > Max=%d.\n", uNumAttachments));
523 uNumAttachments = MAX_DEVICES;
524 }
525
526 /* Find the relevant ports/IDs, i.e the ones to which a HD is attached. */
527 for (size_t j = 0; j < uNumAttachments; ++j)
528 {
529 IMediumAttachment *pMediumAtt = atts[j];
530 LONG lPortNum = 0;
531 hrc = pMediumAtt->COMGETTER(Port)(&lPortNum); H();
532 if (SUCCEEDED(hrc))
533 {
534 DeviceType_T lType;
535 hrc = pMediumAtt->COMGETTER(Type)(&lType); H();
536 if (SUCCEEDED(hrc) && lType == DeviceType_HardDisk)
537 {
538 /* find min port number used for HD */
539 if (lPortNum < lPortLUN[0])
540 lPortLUN[0] = lPortNum;
541 lPortUsed[u32HDCount++] = lPortNum;
542 LogFlowFunc(("HD port Count=%d\n", u32HDCount));
543 }
544 }
545 }
546
547
548 /* Pick only the top 4 used HD Ports as CMOS doesn't have space
549 * to save details for all 30 ports
550 */
551 uint32_t u32MaxPortCount = MAX_BIOS_LUN_COUNT;
552 if (u32HDCount < MAX_BIOS_LUN_COUNT)
553 u32MaxPortCount = u32HDCount;
554 for (size_t j = 1; j < u32MaxPortCount; j++)
555 lPortLUN[j] = GetNextUsedPort(lPortUsed, lPortLUN[j-1], u32HDCount);
556 if (pBiosCfg)
557 {
558 for (size_t j = 0; j < u32MaxPortCount; j++)
559 {
560 InsertConfigInteger(pBiosCfg, s_apszBiosConfig[j], lPortLUN[j]);
561 LogFlowFunc(("Top %d HBA ports = %s, %d\n", j, s_apszBiosConfig[j], lPortLUN[j]));
562 }
563 }
564 return VINF_SUCCESS;
565}
566
567#ifdef VBOX_WITH_PCI_PASSTHROUGH
568HRESULT Console::i_attachRawPCIDevices(PUVM pUVM, BusAssignmentManager *pBusMgr, PCFGMNODE pDevices)
569{
570# ifndef VBOX_WITH_EXTPACK
571 RT_NOREF(pUVM);
572# endif
573 HRESULT hrc = S_OK;
574 PCFGMNODE pInst, pCfg, pLunL0, pLunL1;
575
576 SafeIfaceArray<IPCIDeviceAttachment> assignments;
577 ComPtr<IMachine> aMachine = i_machine();
578
579 hrc = aMachine->COMGETTER(PCIDeviceAssignments)(ComSafeArrayAsOutParam(assignments));
580 if ( hrc != S_OK
581 || assignments.size() < 1)
582 return hrc;
583
584 /*
585 * PCI passthrough is only available if the proper ExtPack is installed.
586 *
587 * Note. Configuring PCI passthrough here and providing messages about
588 * the missing extpack isn't exactly clean, but it is a necessary evil
589 * to patch over legacy compatability issues introduced by the new
590 * distribution model.
591 */
592# ifdef VBOX_WITH_EXTPACK
593 static const char *s_pszPCIRawExtPackName = "Oracle VM VirtualBox Extension Pack";
594 if (!mptrExtPackManager->i_isExtPackUsable(s_pszPCIRawExtPackName))
595 /* Always fatal! */
596 return pVMM->pfnVMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
597 N_("Implementation of the PCI passthrough framework not found!\n"
598 "The VM cannot be started. To fix this problem, either "
599 "install the '%s' or disable PCI passthrough via VBoxManage"),
600 s_pszPCIRawExtPackName);
601# endif
602
603 /* Now actually add devices */
604 PCFGMNODE pPCIDevs = NULL;
605
606 if (assignments.size() > 0)
607 {
608 InsertConfigNode(pDevices, "pciraw", &pPCIDevs);
609
610 PCFGMNODE pRoot = CFGMR3GetParent(pDevices); Assert(pRoot);
611
612 /* Tell PGM to tell GPCIRaw about guest mappings. */
613 CFGMR3InsertNode(pRoot, "PGM", NULL);
614 InsertConfigInteger(CFGMR3GetChild(pRoot, "PGM"), "PciPassThrough", 1);
615
616 /*
617 * Currently, using IOMMU needed for PCI passthrough
618 * requires RAM preallocation.
619 */
620 /** @todo check if we can lift this requirement */
621 CFGMR3RemoveValue(pRoot, "RamPreAlloc");
622 InsertConfigInteger(pRoot, "RamPreAlloc", 1);
623 }
624
625 for (size_t iDev = 0; iDev < assignments.size(); iDev++)
626 {
627 ComPtr<IPCIDeviceAttachment> const assignment = assignments[iDev];
628
629 LONG host;
630 hrc = assignment->COMGETTER(HostAddress)(&host); H();
631 LONG guest;
632 hrc = assignment->COMGETTER(GuestAddress)(&guest); H();
633 Bstr bstrDevName;
634 hrc = assignment->COMGETTER(Name)(bstrDevName.asOutParam()); H();
635
636 InsertConfigNodeF(pPCIDevs, &pInst, "%d", iDev);
637 InsertConfigInteger(pInst, "Trusted", 1);
638
639 PCIBusAddress HostPCIAddress(host);
640 Assert(HostPCIAddress.valid());
641 InsertConfigNode(pInst, "Config", &pCfg);
642 InsertConfigString(pCfg, "DeviceName", bstrDevName);
643
644 InsertConfigInteger(pCfg, "DetachHostDriver", 1);
645 InsertConfigInteger(pCfg, "HostPCIBusNo", HostPCIAddress.miBus);
646 InsertConfigInteger(pCfg, "HostPCIDeviceNo", HostPCIAddress.miDevice);
647 InsertConfigInteger(pCfg, "HostPCIFunctionNo", HostPCIAddress.miFn);
648
649 PCIBusAddress GuestPCIAddress(guest);
650 Assert(GuestPCIAddress.valid());
651 hrc = pBusMgr->assignHostPCIDevice("pciraw", pInst, HostPCIAddress, GuestPCIAddress, true);
652 if (hrc != S_OK)
653 return hrc;
654
655 InsertConfigInteger(pCfg, "GuestPCIBusNo", GuestPCIAddress.miBus);
656 InsertConfigInteger(pCfg, "GuestPCIDeviceNo", GuestPCIAddress.miDevice);
657 InsertConfigInteger(pCfg, "GuestPCIFunctionNo", GuestPCIAddress.miFn);
658
659 /* the driver */
660 InsertConfigNode(pInst, "LUN#0", &pLunL0);
661 InsertConfigString(pLunL0, "Driver", "pciraw");
662 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
663
664 /* the Main driver */
665 InsertConfigString(pLunL1, "Driver", "MainPciRaw");
666 InsertConfigNode(pLunL1, "Config", &pCfg);
667 PCIRawDev *pMainDev = new PCIRawDev(this);
668# error This is not allowed any more
669 InsertConfigInteger(pCfg, "Object", (uintptr_t)pMainDev);
670 }
671
672 return hrc;
673}
674#endif
675
676
677/**
678 * Updates the device type for a LED.
679 *
680 * @param penmSubTypeEntry The sub-type entry to update.
681 * @param enmNewType The new type.
682 */
683void Console::i_setLedType(DeviceType_T *penmSubTypeEntry, DeviceType_T enmNewType)
684{
685 /*
686 * ASSUMES no race conditions here wrt concurrent type updating.
687 */
688 if (*penmSubTypeEntry != enmNewType)
689 {
690 *penmSubTypeEntry = enmNewType;
691 ASMAtomicIncU32(&muLedGen);
692 }
693}
694
695
696/**
697 * Allocate a set of LEDs.
698 *
699 * This grabs a maLedSets entry and populates it with @a cLeds.
700 *
701 * @returns Index into maLedSets.
702 * @param cLeds The number of LEDs in the set.
703 * @param fTypes Bitmask of DeviceType_T values, e.g.
704 * RT_BIT_32(DeviceType_Network).
705 * @param ppaSubTypes When not NULL, subtypes for each LED and return the
706 * array pointer here.
707 */
708uint32_t Console::i_allocateDriverLeds(uint32_t cLeds, uint32_t fTypes, DeviceType_T **ppaSubTypes)
709{
710 Assert(cLeds > 0);
711 Assert(cLeds < 1024); /* Adjust if any driver supports >=1024 units! */
712 Assert(!(fTypes & (RT_BIT_32(DeviceType_Null) | ~(RT_BIT_32(DeviceType_End) - 1))));
713
714 /* Preallocate the arrays we need, bunching them together. */
715 AssertCompile((unsigned)DeviceType_Null == 0);
716 PPDMLED volatile *papLeds = (PPDMLED volatile *)RTMemAllocZ( (sizeof(PPDMLED) + (ppaSubTypes ? sizeof(**ppaSubTypes) : 0))
717 * cLeds);
718 AssertStmt(papLeds, throw E_OUTOFMEMORY);
719
720 /* Take the LED lock in allocation mode and see if there are more LED set entries availalbe. */
721 {
722 AutoWriteLock alock(mLedLock COMMA_LOCKVAL_SRC_POS);
723 uint32_t const idxLedSet = mcLedSets;
724 if (idxLedSet < RT_ELEMENTS(maLedSets))
725 {
726 /* Initialize the set and return the index. */
727 PLEDSET pLS = &maLedSets[idxLedSet];
728 pLS->papLeds = papLeds;
729 pLS->cLeds = cLeds;
730 pLS->fTypes = fTypes;
731 if (ppaSubTypes)
732 *ppaSubTypes = pLS->paSubTypes = (DeviceType_T *)&papLeds[cLeds];
733 else
734 pLS->paSubTypes = NULL;
735
736 mcLedSets = idxLedSet + 1;
737 LogRel2(("return idxLedSet=%d (mcLedSets=%u out of max %zu)\n", idxLedSet, mcLedSets, RT_ELEMENTS(maLedSets)));
738 return idxLedSet;
739 }
740 }
741
742 RTMemFree((void *)papLeds);
743 AssertFailed();
744 throw ConfigError("AllocateDriverPapLeds", VERR_OUT_OF_RANGE, "Too many LED sets");
745}
746
747
748/**
749 * @throws ConfigError and std::bad_alloc.
750 */
751void Console::i_attachStatusDriver(PCFGMNODE pCtlInst, uint32_t fTypes, uint32_t cLeds, DeviceType_T **ppaSubTypes,
752 Console::MediumAttachmentMap *pmapMediumAttachments,
753 const char *pcszDevice, unsigned uInstance)
754{
755 PCFGMNODE pLunL0;
756 InsertConfigNode(pCtlInst, "LUN#999", &pLunL0);
757 InsertConfigString(pLunL0, "Driver", "MainStatus");
758 PCFGMNODE pCfg;
759 InsertConfigNode(pLunL0, "Config", &pCfg);
760 uint32_t const iLedSet = i_allocateDriverLeds(cLeds, fTypes, ppaSubTypes);
761 InsertConfigInteger(pCfg, "iLedSet", iLedSet);
762
763 InsertConfigInteger(pCfg, "HasMediumAttachments", pmapMediumAttachments != NULL);
764 if (pmapMediumAttachments)
765 {
766 AssertPtr(pcszDevice);
767 InsertConfigStringF(pCfg, "DeviceInstance", "%s/%u", pcszDevice, uInstance);
768 }
769 InsertConfigInteger(pCfg, "First", 0);
770 InsertConfigInteger(pCfg, "Last", cLeds - 1);
771}
772
773
774/**
775 * @throws ConfigError and std::bad_alloc.
776 */
777void Console::i_attachStatusDriver(PCFGMNODE pCtlInst, DeviceType_T enmType, uint32_t cLeds /*= 1*/)
778{
779 Assert(enmType > DeviceType_Null && enmType < DeviceType_End);
780 i_attachStatusDriver(pCtlInst, RT_BIT_32(enmType), cLeds, NULL, NULL, NULL, 0);
781}
782
783
784/**
785 * Construct the VM configuration tree (CFGM).
786 *
787 * This is a callback for VMR3Create() call. It is called from CFGMR3Init() in
788 * the emulation thread (EMT). Any per thread COM/XPCOM initialization is done
789 * here.
790 *
791 * @returns VBox status code.
792 * @param pUVM The user mode VM handle.
793 * @param pVM The cross context VM handle.
794 * @param pVMM The VMM ring-3 vtable.
795 * @param pvConsole Pointer to the VMPowerUpTask object.
796 *
797 * @note Locks the Console object for writing.
798 */
799/*static*/ DECLCALLBACK(int)
800Console::i_configConstructor(PUVM pUVM, PVM pVM, PCVMMR3VTABLE pVMM, void *pvConsole)
801{
802 LogFlowFuncEnter();
803
804 AssertReturn(pvConsole, VERR_INVALID_POINTER);
805 ComObjPtr<Console> pConsole = static_cast<Console *>(pvConsole);
806
807 AutoCaller autoCaller(pConsole);
808 AssertComRCReturn(autoCaller.hrc(), VERR_ACCESS_DENIED);
809
810 /* lock the console because we widely use internal fields and methods */
811 AutoWriteLock alock(pConsole COMMA_LOCKVAL_SRC_POS);
812
813 /*
814 * Set the VM handle and do the rest of the job in an worker method so we
815 * can easily reset the VM handle on failure.
816 */
817 pConsole->mpUVM = pUVM;
818 pVMM->pfnVMR3RetainUVM(pUVM);
819 int vrc;
820 try
821 {
822 vrc = pConsole->i_configConstructorInner(pUVM, pVM, pVMM, &alock);
823 }
824 catch (...)
825 {
826 vrc = VERR_UNEXPECTED_EXCEPTION;
827 }
828 if (RT_FAILURE(vrc))
829 {
830 pConsole->mpUVM = NULL;
831 pVMM->pfnVMR3ReleaseUVM(pUVM);
832 }
833
834 return vrc;
835}
836
837
838/**
839 * Worker for configConstructor.
840 *
841 * @return VBox status code.
842 * @param pUVM The user mode VM handle.
843 * @param pVM The cross context VM handle.
844 * @param pVMM The VMM vtable.
845 * @param pAlock The automatic lock instance. This is for when we have
846 * to leave it in order to avoid deadlocks (ext packs and
847 * more).
848 */
849int Console::i_configConstructorInner(PUVM pUVM, PVM pVM, PCVMMR3VTABLE pVMM, AutoWriteLock *pAlock)
850{
851 RT_NOREF(pVM /* when everything is disabled */);
852 VMMDev *pVMMDev = m_pVMMDev; Assert(pVMMDev);
853 ComPtr<IMachine> pMachine = i_machine();
854
855 int vrc;
856 HRESULT hrc;
857 Utf8Str strTmp;
858 Bstr bstr;
859
860#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
861
862 /*
863 * Get necessary objects and frequently used parameters.
864 */
865 ComPtr<IVirtualBox> virtualBox;
866 hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam()); H();
867
868 ComPtr<IHost> host;
869 hrc = virtualBox->COMGETTER(Host)(host.asOutParam()); H();
870
871 ComPtr<ISystemProperties> systemProperties;
872 hrc = virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam()); H();
873
874 ComPtr<IBIOSSettings> biosSettings;
875 hrc = pMachine->COMGETTER(BIOSSettings)(biosSettings.asOutParam()); H();
876
877 ComPtr<INvramStore> nvramStore;
878 hrc = pMachine->COMGETTER(NonVolatileStore)(nvramStore.asOutParam()); H();
879
880 hrc = pMachine->COMGETTER(HardwareUUID)(bstr.asOutParam()); H();
881 RTUUID HardwareUuid;
882 vrc = RTUuidFromUtf16(&HardwareUuid, bstr.raw());
883 AssertRCReturn(vrc, vrc);
884
885 ULONG cRamMBs;
886 hrc = pMachine->COMGETTER(MemorySize)(&cRamMBs); H();
887#if 0 /* enable to play with lots of memory. */
888 if (RTEnvExist("VBOX_RAM_SIZE"))
889 cRamMBs = RTStrToUInt64(RTEnvGet("VBOX_RAM_SIZE"));
890#endif
891 uint64_t const cbRam = cRamMBs * (uint64_t)_1M;
892 uint32_t cbRamHole = MM_RAM_HOLE_SIZE_DEFAULT;
893 uint64_t uMcfgBase = 0;
894 uint32_t cbMcfgLength = 0;
895
896 ParavirtProvider_T enmParavirtProvider;
897 hrc = pMachine->GetEffectiveParavirtProvider(&enmParavirtProvider); H();
898
899 Bstr strParavirtDebug;
900 hrc = pMachine->COMGETTER(ParavirtDebug)(strParavirtDebug.asOutParam()); H();
901
902 BOOL fIOAPIC;
903 uint32_t uIoApicPciAddress = NIL_PCIBDF;
904 hrc = biosSettings->COMGETTER(IOAPICEnabled)(&fIOAPIC); H();
905
906 ChipsetType_T chipsetType;
907 hrc = pMachine->COMGETTER(ChipsetType)(&chipsetType); H();
908 if (chipsetType == ChipsetType_ICH9)
909 {
910 /* We'd better have 0x10000000 region, to cover 256 buses but this put
911 * too much load on hypervisor heap. Linux 4.8 currently complains with
912 * ``acpi PNP0A03:00: [Firmware Info]: MMCONFIG for domain 0000 [bus 00-3f]
913 * only partially covers this bridge'' */
914 cbMcfgLength = 0x4000000; //0x10000000;
915 cbRamHole += cbMcfgLength;
916 uMcfgBase = _4G - cbRamHole;
917 }
918
919 /* Get the CPU profile name. */
920 Bstr bstrCpuProfile;
921 hrc = pMachine->COMGETTER(CPUProfile)(bstrCpuProfile.asOutParam()); H();
922
923 /* Check if long mode is enabled. */
924 BOOL fIsGuest64Bit;
925 hrc = pMachine->GetCPUProperty(CPUPropertyType_LongMode, &fIsGuest64Bit); H();
926
927 /*
928 * Figure out the IOMMU config.
929 */
930#if defined(VBOX_WITH_IOMMU_AMD) || defined(VBOX_WITH_IOMMU_INTEL)
931 IommuType_T enmIommuType;
932 hrc = pMachine->COMGETTER(IommuType)(&enmIommuType); H();
933
934 /* Resolve 'automatic' type to an Intel or AMD IOMMU based on the host CPU. */
935 if (enmIommuType == IommuType_Automatic)
936 {
937 if ( bstrCpuProfile.startsWith("AMD")
938 || bstrCpuProfile.startsWith("Quad-Core AMD")
939 || bstrCpuProfile.startsWith("Hygon"))
940 enmIommuType = IommuType_AMD;
941 else if (bstrCpuProfile.startsWith("Intel"))
942 {
943 if ( bstrCpuProfile.equals("Intel 8086")
944 || bstrCpuProfile.equals("Intel 80186")
945 || bstrCpuProfile.equals("Intel 80286")
946 || bstrCpuProfile.equals("Intel 80386")
947 || bstrCpuProfile.equals("Intel 80486"))
948 enmIommuType = IommuType_None;
949 else
950 enmIommuType = IommuType_Intel;
951 }
952# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
953 else if (ASMIsAmdCpu())
954 enmIommuType = IommuType_AMD;
955 else if (ASMIsIntelCpu())
956 enmIommuType = IommuType_Intel;
957# endif
958 else
959 {
960 /** @todo Should we handle other CPUs like Shanghai, VIA etc. here? */
961 LogRel(("WARNING! Unrecognized CPU type, IOMMU disabled.\n"));
962 enmIommuType = IommuType_None;
963 }
964 }
965
966 if (enmIommuType == IommuType_AMD)
967 {
968# ifdef VBOX_WITH_IOMMU_AMD
969 /*
970 * Reserve the specific PCI address of the "SB I/O APIC" when using
971 * an AMD IOMMU. Required by Linux guests, see @bugref{9654#c23}.
972 */
973 uIoApicPciAddress = VBOX_PCI_BDF_SB_IOAPIC;
974# else
975 LogRel(("WARNING! AMD IOMMU not supported, IOMMU disabled.\n"));
976 enmIommuType = IommuType_None;
977# endif
978 }
979
980 if (enmIommuType == IommuType_Intel)
981 {
982# ifdef VBOX_WITH_IOMMU_INTEL
983 /*
984 * Reserve a unique PCI address for the I/O APIC when using
985 * an Intel IOMMU. For convenience we use the same address as
986 * we do on AMD, see @bugref{9967#c13}.
987 */
988 uIoApicPciAddress = VBOX_PCI_BDF_SB_IOAPIC;
989# else
990 LogRel(("WARNING! Intel IOMMU not supported, IOMMU disabled.\n"));
991 enmIommuType = IommuType_None;
992# endif
993 }
994
995 if ( enmIommuType == IommuType_AMD
996 || enmIommuType == IommuType_Intel)
997 {
998 if (chipsetType != ChipsetType_ICH9)
999 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1000 N_("IOMMU uses MSIs which requires the ICH9 chipset implementation."));
1001 if (!fIOAPIC)
1002 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1003 N_("IOMMU requires an I/O APIC for remapping interrupts."));
1004 }
1005#else
1006 IommuType_T const enmIommuType = IommuType_None;
1007#endif
1008
1009 /* Instantiate the bus assignment manager. */
1010 Assert(enmIommuType != IommuType_Automatic);
1011 BusAssignmentManager *pBusMgr = mBusMgr = BusAssignmentManager::createInstance(pVMM, chipsetType, enmIommuType);
1012
1013 ULONG cCpus = 1;
1014 hrc = pMachine->COMGETTER(CPUCount)(&cCpus); H();
1015
1016 ULONG ulCpuExecutionCap = 100;
1017 hrc = pMachine->COMGETTER(CPUExecutionCap)(&ulCpuExecutionCap); H();
1018
1019 Bstr osTypeId;
1020 hrc = pMachine->COMGETTER(OSTypeId)(osTypeId.asOutParam()); H();
1021 LogRel(("Guest OS type: '%s'\n", Utf8Str(osTypeId).c_str()));
1022
1023 APICMode_T apicMode;
1024 hrc = biosSettings->COMGETTER(APICMode)(&apicMode); H();
1025 uint32_t uFwAPIC;
1026 switch (apicMode)
1027 {
1028 case APICMode_Disabled:
1029 uFwAPIC = 0;
1030 break;
1031 case APICMode_APIC:
1032 uFwAPIC = 1;
1033 break;
1034 case APICMode_X2APIC:
1035 uFwAPIC = 2;
1036 break;
1037 default:
1038 AssertMsgFailed(("Invalid APICMode=%d\n", apicMode));
1039 uFwAPIC = 1;
1040 break;
1041 }
1042
1043 ComPtr<IGuestOSType> pGuestOSType;
1044 virtualBox->GetGuestOSType(osTypeId.raw(), pGuestOSType.asOutParam());
1045
1046 BOOL fOsXGuest = FALSE;
1047 BOOL fWinGuest = FALSE;
1048 BOOL fOs2Guest = FALSE;
1049 BOOL fW9xGuest = FALSE;
1050 BOOL fDosGuest = FALSE;
1051 if (!pGuestOSType.isNull())
1052 {
1053 Bstr guestTypeFamilyId;
1054 hrc = pGuestOSType->COMGETTER(FamilyId)(guestTypeFamilyId.asOutParam()); H();
1055 fOsXGuest = guestTypeFamilyId == Bstr("MacOS");
1056 fWinGuest = guestTypeFamilyId == Bstr("Windows");
1057 fOs2Guest = osTypeId.startsWith("OS2");
1058 fW9xGuest = osTypeId.startsWith("Windows9"); /* Does not include Windows Me. */
1059 fDosGuest = osTypeId.startsWith("DOS") || osTypeId.startsWith("Windows31");
1060 }
1061
1062 ULONG maxNetworkAdapters;
1063 hrc = systemProperties->GetMaxNetworkAdapters(chipsetType, &maxNetworkAdapters); H();
1064
1065 /*
1066 * Get root node first.
1067 * This is the only node in the tree.
1068 */
1069 PCFGMNODE pRoot = pVMM->pfnCFGMR3GetRootU(pUVM);
1070 Assert(pRoot);
1071
1072 // catching throws from InsertConfigString and friends.
1073 try
1074 {
1075
1076 /*
1077 * Set the root (and VMM) level values.
1078 */
1079 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
1080 InsertConfigString(pRoot, "Name", bstr);
1081 InsertConfigBytes(pRoot, "UUID", &HardwareUuid, sizeof(HardwareUuid));
1082 InsertConfigInteger(pRoot, "RamSize", cbRam);
1083 InsertConfigInteger(pRoot, "RamHoleSize", cbRamHole);
1084 InsertConfigInteger(pRoot, "NumCPUs", cCpus);
1085 InsertConfigInteger(pRoot, "CpuExecutionCap", ulCpuExecutionCap);
1086 InsertConfigInteger(pRoot, "TimerMillies", 10);
1087
1088 BOOL fPageFusion = FALSE;
1089 hrc = pMachine->COMGETTER(PageFusionEnabled)(&fPageFusion); H();
1090 InsertConfigInteger(pRoot, "PageFusionAllowed", fPageFusion); /* boolean */
1091
1092 /* Not necessary, but makes sure this setting ends up in the release log. */
1093 ULONG ulBalloonSize = 0;
1094 hrc = pMachine->COMGETTER(MemoryBalloonSize)(&ulBalloonSize); H();
1095 InsertConfigInteger(pRoot, "MemBalloonSize", ulBalloonSize);
1096
1097 /*
1098 * EM values (before CPUM as it may need to set IemExecutesAll).
1099 */
1100 PCFGMNODE pEM;
1101 InsertConfigNode(pRoot, "EM", &pEM);
1102
1103 /* Triple fault behavior. */
1104 BOOL fTripleFaultReset = false;
1105 hrc = pMachine->GetCPUProperty(CPUPropertyType_TripleFaultReset, &fTripleFaultReset); H();
1106 InsertConfigInteger(pEM, "TripleFaultReset", fTripleFaultReset);
1107
1108 /*
1109 * CPUM values.
1110 */
1111 PCFGMNODE pCPUM;
1112 InsertConfigNode(pRoot, "CPUM", &pCPUM);
1113 PCFGMNODE pIsaExts;
1114 InsertConfigNode(pCPUM, "IsaExts", &pIsaExts);
1115
1116 /* Host CPUID leaf overrides. */
1117 for (uint32_t iOrdinal = 0; iOrdinal < _4K; iOrdinal++)
1118 {
1119 ULONG uLeaf, uSubLeaf, uEax, uEbx, uEcx, uEdx;
1120 hrc = pMachine->GetCPUIDLeafByOrdinal(iOrdinal, &uLeaf, &uSubLeaf, &uEax, &uEbx, &uEcx, &uEdx);
1121 if (hrc == E_INVALIDARG)
1122 break;
1123 H();
1124 PCFGMNODE pLeaf;
1125 InsertConfigNode(pCPUM, Utf8StrFmt("HostCPUID/%RX32", uLeaf).c_str(), &pLeaf);
1126 /** @todo Figure out how to tell the VMM about uSubLeaf */
1127 InsertConfigInteger(pLeaf, "eax", uEax);
1128 InsertConfigInteger(pLeaf, "ebx", uEbx);
1129 InsertConfigInteger(pLeaf, "ecx", uEcx);
1130 InsertConfigInteger(pLeaf, "edx", uEdx);
1131 }
1132
1133 /* We must limit CPUID count for Windows NT 4, as otherwise it stops
1134 with error 0x3e (MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED). */
1135 if (osTypeId == "WindowsNT4")
1136 {
1137 LogRel(("Limiting CPUID leaf count for NT4 guests\n"));
1138 InsertConfigInteger(pCPUM, "NT4LeafLimit", true);
1139 }
1140
1141 if (fOsXGuest)
1142 {
1143 /* Expose extended MWAIT features to Mac OS X guests. */
1144 LogRel(("Using MWAIT extensions\n"));
1145 InsertConfigInteger(pIsaExts, "MWaitExtensions", true);
1146
1147 /* Fake the CPU family/model so the guest works. This is partly
1148 because older mac releases really doesn't work on newer cpus,
1149 and partly because mac os x expects more from systems with newer
1150 cpus (MSRs, power features, whatever). */
1151 uint32_t uMaxIntelFamilyModelStep = UINT32_MAX;
1152 if ( osTypeId == "MacOS"
1153 || osTypeId == "MacOS_64")
1154 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482. */
1155 else if ( osTypeId == "MacOS106"
1156 || osTypeId == "MacOS106_64")
1157 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */
1158 else if ( osTypeId == "MacOS107"
1159 || osTypeId == "MacOS107_64")
1160 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */ /** @todo figure out
1161 what is required here. */
1162 else if ( osTypeId == "MacOS108"
1163 || osTypeId == "MacOS108_64")
1164 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */ /** @todo figure out
1165 what is required here. */
1166 else if ( osTypeId == "MacOS109"
1167 || osTypeId == "MacOS109_64")
1168 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */ /** @todo figure
1169 out what is required here. */
1170 if (uMaxIntelFamilyModelStep != UINT32_MAX)
1171 InsertConfigInteger(pCPUM, "MaxIntelFamilyModelStep", uMaxIntelFamilyModelStep);
1172 }
1173
1174 /* CPU Portability level, */
1175 ULONG uCpuIdPortabilityLevel = 0;
1176 hrc = pMachine->COMGETTER(CPUIDPortabilityLevel)(&uCpuIdPortabilityLevel); H();
1177 InsertConfigInteger(pCPUM, "PortableCpuIdLevel", uCpuIdPortabilityLevel);
1178
1179 /* Physical Address Extension (PAE) */
1180 BOOL fEnablePAE = false;
1181 hrc = pMachine->GetCPUProperty(CPUPropertyType_PAE, &fEnablePAE); H();
1182 fEnablePAE |= fIsGuest64Bit;
1183 InsertConfigInteger(pRoot, "EnablePAE", fEnablePAE);
1184
1185 /* 64-bit guests (long mode) */
1186 InsertConfigInteger(pCPUM, "Enable64bit", fIsGuest64Bit);
1187
1188 /* APIC/X2APIC configuration */
1189 BOOL fEnableAPIC = true;
1190 BOOL fEnableX2APIC = true;
1191 hrc = pMachine->GetCPUProperty(CPUPropertyType_APIC, &fEnableAPIC); H();
1192 hrc = pMachine->GetCPUProperty(CPUPropertyType_X2APIC, &fEnableX2APIC); H();
1193 if (fEnableX2APIC)
1194 Assert(fEnableAPIC);
1195
1196 /* CPUM profile name. */
1197 InsertConfigString(pCPUM, "GuestCpuName", bstrCpuProfile);
1198
1199 /*
1200 * Temporary(?) hack to make sure we emulate the ancient 16-bit CPUs
1201 * correctly. There are way too many #UDs we'll miss using VT-x,
1202 * raw-mode or qemu for the 186 and 286, while we'll get undefined opcodes
1203 * dead wrong on 8086 (see http://www.os2museum.com/wp/undocumented-8086-opcodes/).
1204 */
1205 if ( bstrCpuProfile.equals("Intel 80386") /* just for now */
1206 || bstrCpuProfile.equals("Intel 80286")
1207 || bstrCpuProfile.equals("Intel 80186")
1208 || bstrCpuProfile.equals("Nec V20")
1209 || bstrCpuProfile.equals("Intel 8086") )
1210 {
1211 InsertConfigInteger(pEM, "IemExecutesAll", true);
1212 if (!bstrCpuProfile.equals("Intel 80386"))
1213 {
1214 fEnableAPIC = false;
1215 fIOAPIC = false;
1216 }
1217 fEnableX2APIC = false;
1218 }
1219
1220 /* Adjust firmware APIC handling to stay within the VCPU limits. */
1221 if (uFwAPIC == 2 && !fEnableX2APIC)
1222 {
1223 if (fEnableAPIC)
1224 uFwAPIC = 1;
1225 else
1226 uFwAPIC = 0;
1227 LogRel(("Limiting the firmware APIC level from x2APIC to %s\n", fEnableAPIC ? "APIC" : "Disabled"));
1228 }
1229 else if (uFwAPIC == 1 && !fEnableAPIC)
1230 {
1231 uFwAPIC = 0;
1232 LogRel(("Limiting the firmware APIC level from APIC to Disabled\n"));
1233 }
1234
1235 /* Speculation Control. */
1236 BOOL fSpecCtrl = FALSE;
1237 hrc = pMachine->GetCPUProperty(CPUPropertyType_SpecCtrl, &fSpecCtrl); H();
1238 InsertConfigInteger(pCPUM, "SpecCtrl", fSpecCtrl);
1239
1240 /* Nested VT-x / AMD-V. */
1241 BOOL fNestedHWVirt = FALSE;
1242 hrc = pMachine->GetCPUProperty(CPUPropertyType_HWVirt, &fNestedHWVirt); H();
1243 InsertConfigInteger(pCPUM, "NestedHWVirt", fNestedHWVirt ? true : false);
1244
1245 /*
1246 * Hardware virtualization extensions.
1247 */
1248 /* Sanitize valid/useful APIC combinations, see @bugref{8868}. */
1249 if (!fEnableAPIC)
1250 {
1251 if (fIsGuest64Bit)
1252 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1253 N_("Cannot disable the APIC for a 64-bit guest."));
1254 if (cCpus > 1)
1255 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1256 N_("Cannot disable the APIC for an SMP guest."));
1257 if (fIOAPIC)
1258 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1259 N_("Cannot disable the APIC when the I/O APIC is present."));
1260 }
1261
1262 BOOL fHMEnabled;
1263 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_Enabled, &fHMEnabled); H();
1264 if (cCpus > 1 && !fHMEnabled)
1265 {
1266 LogRel(("Forced fHMEnabled to TRUE by SMP guest.\n"));
1267 fHMEnabled = TRUE;
1268 }
1269
1270 BOOL fHMForced;
1271 fHMEnabled = fHMForced = TRUE;
1272 LogRel(("fHMForced=true - No raw-mode support in this build!\n"));
1273 if (!fHMForced) /* No need to query if already forced above. */
1274 {
1275 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_Force, &fHMForced); H();
1276 if (fHMForced)
1277 LogRel(("fHMForced=true - HWVirtExPropertyType_Force\n"));
1278 }
1279 InsertConfigInteger(pRoot, "HMEnabled", fHMEnabled);
1280
1281 /* /HM/xyz */
1282 PCFGMNODE pHM;
1283 InsertConfigNode(pRoot, "HM", &pHM);
1284 InsertConfigInteger(pHM, "HMForced", fHMForced);
1285 if (fHMEnabled)
1286 {
1287 /* Indicate whether 64-bit guests are supported or not. */
1288 InsertConfigInteger(pHM, "64bitEnabled", fIsGuest64Bit);
1289
1290 /** @todo Not exactly pretty to check strings; VBOXOSTYPE would be better,
1291 but that requires quite a bit of API change in Main. */
1292 if ( fIOAPIC
1293 && ( osTypeId == "WindowsNT4"
1294 || osTypeId == "Windows2000"
1295 || osTypeId == "WindowsXP"
1296 || osTypeId == "Windows2003"))
1297 {
1298 /* Only allow TPR patching for NT, Win2k, XP and Windows Server 2003. (32 bits mode)
1299 * We may want to consider adding more guest OSes (Solaris) later on.
1300 */
1301 InsertConfigInteger(pHM, "TPRPatchingEnabled", 1);
1302 }
1303 }
1304
1305 /* HWVirtEx exclusive mode */
1306 BOOL fHMExclusive = true;
1307 hrc = systemProperties->COMGETTER(ExclusiveHwVirt)(&fHMExclusive); H();
1308 InsertConfigInteger(pHM, "Exclusive", fHMExclusive);
1309
1310 /* Nested paging (VT-x/AMD-V) */
1311 BOOL fEnableNestedPaging = false;
1312 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_NestedPaging, &fEnableNestedPaging); H();
1313 InsertConfigInteger(pHM, "EnableNestedPaging", fEnableNestedPaging);
1314
1315 /* Large pages; requires nested paging */
1316 BOOL fEnableLargePages = false;
1317 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_LargePages, &fEnableLargePages); H();
1318 InsertConfigInteger(pHM, "EnableLargePages", fEnableLargePages);
1319
1320 /* VPID (VT-x) */
1321 BOOL fEnableVPID = false;
1322 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_VPID, &fEnableVPID); H();
1323 InsertConfigInteger(pHM, "EnableVPID", fEnableVPID);
1324
1325 /* Unrestricted execution aka UX (VT-x) */
1326 BOOL fEnableUX = false;
1327 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_UnrestrictedExecution, &fEnableUX); H();
1328 InsertConfigInteger(pHM, "EnableUX", fEnableUX);
1329
1330 /* Virtualized VMSAVE/VMLOAD (AMD-V) */
1331 BOOL fVirtVmsaveVmload = true;
1332 hrc = host->GetProcessorFeature(ProcessorFeature_VirtVmsaveVmload, &fVirtVmsaveVmload); H();
1333 InsertConfigInteger(pHM, "SvmVirtVmsaveVmload", fVirtVmsaveVmload);
1334
1335 /* Indirect branch prediction boundraries. */
1336 BOOL fIBPBOnVMExit = false;
1337 hrc = pMachine->GetCPUProperty(CPUPropertyType_IBPBOnVMExit, &fIBPBOnVMExit); H();
1338 InsertConfigInteger(pHM, "IBPBOnVMExit", fIBPBOnVMExit);
1339
1340 BOOL fIBPBOnVMEntry = false;
1341 hrc = pMachine->GetCPUProperty(CPUPropertyType_IBPBOnVMEntry, &fIBPBOnVMEntry); H();
1342 InsertConfigInteger(pHM, "IBPBOnVMEntry", fIBPBOnVMEntry);
1343
1344 BOOL fSpecCtrlByHost = false;
1345 hrc = pMachine->GetCPUProperty(CPUPropertyType_SpecCtrlByHost, &fSpecCtrlByHost); H();
1346 InsertConfigInteger(pHM, "SpecCtrlByHost", fSpecCtrlByHost);
1347
1348 BOOL fL1DFlushOnSched = true;
1349 hrc = pMachine->GetCPUProperty(CPUPropertyType_L1DFlushOnEMTScheduling, &fL1DFlushOnSched); H();
1350 InsertConfigInteger(pHM, "L1DFlushOnSched", fL1DFlushOnSched);
1351
1352 BOOL fL1DFlushOnVMEntry = false;
1353 hrc = pMachine->GetCPUProperty(CPUPropertyType_L1DFlushOnVMEntry, &fL1DFlushOnVMEntry); H();
1354 InsertConfigInteger(pHM, "L1DFlushOnVMEntry", fL1DFlushOnVMEntry);
1355
1356 BOOL fMDSClearOnSched = true;
1357 hrc = pMachine->GetCPUProperty(CPUPropertyType_MDSClearOnEMTScheduling, &fMDSClearOnSched); H();
1358 InsertConfigInteger(pHM, "MDSClearOnSched", fMDSClearOnSched);
1359
1360 BOOL fMDSClearOnVMEntry = false;
1361 hrc = pMachine->GetCPUProperty(CPUPropertyType_MDSClearOnVMEntry, &fMDSClearOnVMEntry); H();
1362 InsertConfigInteger(pHM, "MDSClearOnVMEntry", fMDSClearOnVMEntry);
1363
1364 /* Reset overwrite. */
1365 mfTurnResetIntoPowerOff = GetExtraDataBoth(virtualBox, pMachine,
1366 "VBoxInternal2/TurnResetIntoPowerOff", &strTmp)->equals("1");
1367 if (mfTurnResetIntoPowerOff)
1368 InsertConfigInteger(pRoot, "PowerOffInsteadOfReset", 1);
1369
1370 /* Use NEM rather than HM. */
1371 BOOL fUseNativeApi = false;
1372 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_UseNativeApi, &fUseNativeApi); H();
1373 InsertConfigInteger(pHM, "UseNEMInstead", fUseNativeApi);
1374
1375 /* Enable workaround for missing TLB flush for OS/2 guests, see ticketref:20625. */
1376 if (osTypeId.startsWith("OS2"))
1377 InsertConfigInteger(pHM, "MissingOS2TlbFlushWorkaround", 1);
1378
1379 /*
1380 * NEM
1381 */
1382 PCFGMNODE pNEM;
1383 InsertConfigNode(pRoot, "NEM", &pNEM);
1384 InsertConfigInteger(pNEM, "Allow64BitGuests", fIsGuest64Bit);
1385
1386 /*
1387 * Paravirt. provider.
1388 */
1389 PCFGMNODE pParavirtNode;
1390 InsertConfigNode(pRoot, "GIM", &pParavirtNode);
1391 const char *pcszParavirtProvider;
1392 bool fGimDeviceNeeded = true;
1393 switch (enmParavirtProvider)
1394 {
1395 case ParavirtProvider_None:
1396 pcszParavirtProvider = "None";
1397 fGimDeviceNeeded = false;
1398 break;
1399
1400 case ParavirtProvider_Minimal:
1401 pcszParavirtProvider = "Minimal";
1402 break;
1403
1404 case ParavirtProvider_HyperV:
1405 pcszParavirtProvider = "HyperV";
1406 break;
1407
1408 case ParavirtProvider_KVM:
1409 pcszParavirtProvider = "KVM";
1410 break;
1411
1412 default:
1413 AssertMsgFailed(("Invalid enmParavirtProvider=%d\n", enmParavirtProvider));
1414 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("Invalid paravirt. provider '%d'"),
1415 enmParavirtProvider);
1416 }
1417 InsertConfigString(pParavirtNode, "Provider", pcszParavirtProvider);
1418
1419 /*
1420 * Parse paravirt. debug options.
1421 */
1422 bool fGimDebug = false;
1423 com::Utf8Str strGimDebugAddress = "127.0.0.1";
1424 uint32_t uGimDebugPort = 50000;
1425 if (strParavirtDebug.isNotEmpty())
1426 {
1427 /* Hyper-V debug options. */
1428 if (enmParavirtProvider == ParavirtProvider_HyperV)
1429 {
1430 bool fGimHvDebug = false;
1431 com::Utf8Str strGimHvVendor;
1432 bool fGimHvVsIf = false;
1433 bool fGimHvHypercallIf = false;
1434
1435 size_t uPos = 0;
1436 com::Utf8Str strDebugOptions = strParavirtDebug;
1437 com::Utf8Str strKey;
1438 com::Utf8Str strVal;
1439 while ((uPos = strDebugOptions.parseKeyValue(strKey, strVal, uPos)) != com::Utf8Str::npos)
1440 {
1441 if (strKey == "enabled")
1442 {
1443 if (strVal.toUInt32() == 1)
1444 {
1445 /* Apply defaults.
1446 The defaults are documented in the user manual,
1447 changes need to be reflected accordingly. */
1448 fGimHvDebug = true;
1449 strGimHvVendor = "Microsoft Hv";
1450 fGimHvVsIf = true;
1451 fGimHvHypercallIf = false;
1452 }
1453 /* else: ignore, i.e. don't assert below with 'enabled=0'. */
1454 }
1455 else if (strKey == "address")
1456 strGimDebugAddress = strVal;
1457 else if (strKey == "port")
1458 uGimDebugPort = strVal.toUInt32();
1459 else if (strKey == "vendor")
1460 strGimHvVendor = strVal;
1461 else if (strKey == "vsinterface")
1462 fGimHvVsIf = RT_BOOL(strVal.toUInt32());
1463 else if (strKey == "hypercallinterface")
1464 fGimHvHypercallIf = RT_BOOL(strVal.toUInt32());
1465 else
1466 {
1467 AssertMsgFailed(("Unrecognized Hyper-V debug option '%s'\n", strKey.c_str()));
1468 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1469 N_("Unrecognized Hyper-V debug option '%s' in '%s'"), strKey.c_str(),
1470 strDebugOptions.c_str());
1471 }
1472 }
1473
1474 /* Update HyperV CFGM node with active debug options. */
1475 if (fGimHvDebug)
1476 {
1477 PCFGMNODE pHvNode;
1478 InsertConfigNode(pParavirtNode, "HyperV", &pHvNode);
1479 InsertConfigString(pHvNode, "VendorID", strGimHvVendor);
1480 InsertConfigInteger(pHvNode, "VSInterface", fGimHvVsIf ? 1 : 0);
1481 InsertConfigInteger(pHvNode, "HypercallDebugInterface", fGimHvHypercallIf ? 1 : 0);
1482 fGimDebug = true;
1483 }
1484 }
1485 }
1486
1487 /*
1488 * Guest Compatibility Manager.
1489 */
1490 PCFGMNODE pGcmNode;
1491 uint32_t u32FixerSet = 0;
1492 InsertConfigNode(pRoot, "GCM", &pGcmNode);
1493 /* OS/2 and Win9x guests can run DOS apps so they get
1494 * the DOS specific fixes as well.
1495 */
1496 if (fOs2Guest)
1497 u32FixerSet = GCMFIXER_DBZ_DOS | GCMFIXER_DBZ_OS2;
1498 else if (fW9xGuest)
1499 u32FixerSet = GCMFIXER_DBZ_DOS | GCMFIXER_DBZ_WIN9X;
1500 else if (fDosGuest)
1501 u32FixerSet = GCMFIXER_DBZ_DOS;
1502 InsertConfigInteger(pGcmNode, "FixerSet", u32FixerSet);
1503
1504
1505 /*
1506 * MM values.
1507 */
1508 PCFGMNODE pMM;
1509 InsertConfigNode(pRoot, "MM", &pMM);
1510 InsertConfigInteger(pMM, "CanUseLargerHeap", chipsetType == ChipsetType_ICH9);
1511
1512 /*
1513 * PDM config.
1514 * Load drivers in VBoxC.[so|dll]
1515 */
1516 PCFGMNODE pPDM;
1517 PCFGMNODE pNode;
1518 PCFGMNODE pMod;
1519 InsertConfigNode(pRoot, "PDM", &pPDM);
1520 InsertConfigNode(pPDM, "Devices", &pNode);
1521 InsertConfigNode(pPDM, "Drivers", &pNode);
1522 InsertConfigNode(pNode, "VBoxC", &pMod);
1523#ifdef VBOX_WITH_XPCOM
1524 // VBoxC is located in the components subdirectory
1525 char szPathVBoxC[RTPATH_MAX];
1526 vrc = RTPathAppPrivateArch(szPathVBoxC, RTPATH_MAX - sizeof("/components/VBoxC")); AssertRC(vrc);
1527 strcat(szPathVBoxC, "/components/VBoxC");
1528 InsertConfigString(pMod, "Path", szPathVBoxC);
1529#else
1530 InsertConfigString(pMod, "Path", "VBoxC");
1531#endif
1532
1533
1534 /*
1535 * Block cache settings.
1536 */
1537 PCFGMNODE pPDMBlkCache;
1538 InsertConfigNode(pPDM, "BlkCache", &pPDMBlkCache);
1539
1540 /* I/O cache size */
1541 ULONG ioCacheSize = 5;
1542 hrc = pMachine->COMGETTER(IOCacheSize)(&ioCacheSize); H();
1543 InsertConfigInteger(pPDMBlkCache, "CacheSize", ioCacheSize * _1M);
1544
1545 /*
1546 * Bandwidth groups.
1547 */
1548 ComPtr<IBandwidthControl> bwCtrl;
1549
1550 hrc = pMachine->COMGETTER(BandwidthControl)(bwCtrl.asOutParam()); H();
1551
1552 com::SafeIfaceArray<IBandwidthGroup> bwGroups;
1553 hrc = bwCtrl->GetAllBandwidthGroups(ComSafeArrayAsOutParam(bwGroups)); H();
1554
1555 PCFGMNODE pAc;
1556 InsertConfigNode(pPDM, "AsyncCompletion", &pAc);
1557 PCFGMNODE pAcFile;
1558 InsertConfigNode(pAc, "File", &pAcFile);
1559 PCFGMNODE pAcFileBwGroups;
1560 InsertConfigNode(pAcFile, "BwGroups", &pAcFileBwGroups);
1561#ifdef VBOX_WITH_NETSHAPER
1562 PCFGMNODE pNetworkShaper;
1563 InsertConfigNode(pPDM, "NetworkShaper", &pNetworkShaper);
1564 PCFGMNODE pNetworkBwGroups;
1565 InsertConfigNode(pNetworkShaper, "BwGroups", &pNetworkBwGroups);
1566#endif /* VBOX_WITH_NETSHAPER */
1567
1568 for (size_t i = 0; i < bwGroups.size(); i++)
1569 {
1570 Bstr strName;
1571 hrc = bwGroups[i]->COMGETTER(Name)(strName.asOutParam()); H();
1572 if (strName.isEmpty())
1573 return pVMM->pfnVMR3SetError(pUVM, VERR_CFGM_NO_NODE, RT_SRC_POS, N_("No bandwidth group name specified"));
1574
1575 BandwidthGroupType_T enmType = BandwidthGroupType_Null;
1576 hrc = bwGroups[i]->COMGETTER(Type)(&enmType); H();
1577 LONG64 cMaxBytesPerSec = 0;
1578 hrc = bwGroups[i]->COMGETTER(MaxBytesPerSec)(&cMaxBytesPerSec); H();
1579
1580 if (enmType == BandwidthGroupType_Disk)
1581 {
1582 PCFGMNODE pBwGroup;
1583 InsertConfigNode(pAcFileBwGroups, Utf8Str(strName).c_str(), &pBwGroup);
1584 InsertConfigInteger(pBwGroup, "Max", cMaxBytesPerSec);
1585 InsertConfigInteger(pBwGroup, "Start", cMaxBytesPerSec);
1586 InsertConfigInteger(pBwGroup, "Step", 0);
1587 }
1588#ifdef VBOX_WITH_NETSHAPER
1589 else if (enmType == BandwidthGroupType_Network)
1590 {
1591 /* Network bandwidth groups. */
1592 PCFGMNODE pBwGroup;
1593 InsertConfigNode(pNetworkBwGroups, Utf8Str(strName).c_str(), &pBwGroup);
1594 InsertConfigInteger(pBwGroup, "Max", cMaxBytesPerSec);
1595 }
1596#endif /* VBOX_WITH_NETSHAPER */
1597 }
1598
1599 /*
1600 * Devices
1601 */
1602 PCFGMNODE pDevices = NULL; /* /Devices */
1603 PCFGMNODE pDev = NULL; /* /Devices/Dev/ */
1604 PCFGMNODE pInst = NULL; /* /Devices/Dev/0/ */
1605 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
1606 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
1607 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */
1608 PCFGMNODE pBiosCfg = NULL; /* /Devices/pcbios/0/Config/ */
1609 PCFGMNODE pNetBootCfg = NULL; /* /Devices/pcbios/0/Config/NetBoot/ */
1610
1611 InsertConfigNode(pRoot, "Devices", &pDevices);
1612
1613 /*
1614 * GIM Device
1615 */
1616 if (fGimDeviceNeeded)
1617 {
1618 InsertConfigNode(pDevices, "GIMDev", &pDev);
1619 InsertConfigNode(pDev, "0", &pInst);
1620 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1621 //InsertConfigNode(pInst, "Config", &pCfg);
1622
1623 if (fGimDebug)
1624 {
1625 InsertConfigNode(pInst, "LUN#998", &pLunL0);
1626 InsertConfigString(pLunL0, "Driver", "UDP");
1627 InsertConfigNode(pLunL0, "Config", &pLunL1);
1628 InsertConfigString(pLunL1, "ServerAddress", strGimDebugAddress);
1629 InsertConfigInteger(pLunL1, "ServerPort", uGimDebugPort);
1630 }
1631 }
1632
1633 /*
1634 * PC Arch.
1635 */
1636 InsertConfigNode(pDevices, "pcarch", &pDev);
1637 InsertConfigNode(pDev, "0", &pInst);
1638 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1639 InsertConfigNode(pInst, "Config", &pCfg);
1640
1641 /*
1642 * The time offset
1643 */
1644 LONG64 timeOffset;
1645 hrc = biosSettings->COMGETTER(TimeOffset)(&timeOffset); H();
1646 PCFGMNODE pTMNode;
1647 InsertConfigNode(pRoot, "TM", &pTMNode);
1648 InsertConfigInteger(pTMNode, "UTCOffset", timeOffset * 1000000);
1649
1650 /*
1651 * DMA
1652 */
1653 InsertConfigNode(pDevices, "8237A", &pDev);
1654 InsertConfigNode(pDev, "0", &pInst);
1655 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1656
1657 /*
1658 * PCI buses.
1659 */
1660 uint32_t uIocPCIAddress, uHbcPCIAddress;
1661 switch (chipsetType)
1662 {
1663 default:
1664 AssertFailed();
1665 RT_FALL_THRU();
1666 case ChipsetType_PIIX3:
1667 /* Create the base for adding bridges on demand */
1668 InsertConfigNode(pDevices, "pcibridge", NULL);
1669
1670 InsertConfigNode(pDevices, "pci", &pDev);
1671 uHbcPCIAddress = (0x0 << 16) | 0;
1672 uIocPCIAddress = (0x1 << 16) | 0; // ISA controller
1673 break;
1674 case ChipsetType_ICH9:
1675 /* Create the base for adding bridges on demand */
1676 InsertConfigNode(pDevices, "ich9pcibridge", NULL);
1677
1678 InsertConfigNode(pDevices, "ich9pci", &pDev);
1679 uHbcPCIAddress = (0x1e << 16) | 0;
1680 uIocPCIAddress = (0x1f << 16) | 0; // LPC controller
1681 break;
1682 }
1683 InsertConfigNode(pDev, "0", &pInst);
1684 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1685 InsertConfigNode(pInst, "Config", &pCfg);
1686 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1687 if (chipsetType == ChipsetType_ICH9)
1688 {
1689 /* Provide MCFG info */
1690 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
1691 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
1692
1693#ifdef VBOX_WITH_PCI_PASSTHROUGH
1694 /* Add PCI passthrough devices */
1695 hrc = i_attachRawPCIDevices(pUVM, pBusMgr, pDevices); H();
1696#endif
1697
1698 if (enmIommuType == IommuType_AMD)
1699 {
1700 /* AMD IOMMU. */
1701 InsertConfigNode(pDevices, "iommu-amd", &pDev);
1702 InsertConfigNode(pDev, "0", &pInst);
1703 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1704 InsertConfigNode(pInst, "Config", &pCfg);
1705 hrc = pBusMgr->assignPCIDevice("iommu-amd", pInst); H();
1706
1707 /* The AMD IOMMU device needs to know which PCI slot it's in, see @bugref{9654#c104}. */
1708 {
1709 PCIBusAddress Address;
1710 if (pBusMgr->findPCIAddress("iommu-amd", 0, Address))
1711 {
1712 uint32_t const u32IommuAddress = (Address.miDevice << 16) | Address.miFn;
1713 InsertConfigInteger(pCfg, "PCIAddress", u32IommuAddress);
1714 }
1715 else
1716 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1717 N_("Failed to find PCI address of the assigned IOMMU device!"));
1718 }
1719
1720 PCIBusAddress PCIAddr = PCIBusAddress((int32_t)uIoApicPciAddress);
1721 hrc = pBusMgr->assignPCIDevice("sb-ioapic", NULL /* pCfg */, PCIAddr, true /*fGuestAddressRequired*/); H();
1722 }
1723 else if (enmIommuType == IommuType_Intel)
1724 {
1725 /* Intel IOMMU. */
1726 InsertConfigNode(pDevices, "iommu-intel", &pDev);
1727 InsertConfigNode(pDev, "0", &pInst);
1728 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1729 InsertConfigNode(pInst, "Config", &pCfg);
1730 hrc = pBusMgr->assignPCIDevice("iommu-intel", pInst); H();
1731
1732 PCIBusAddress PCIAddr = PCIBusAddress((int32_t)uIoApicPciAddress);
1733 hrc = pBusMgr->assignPCIDevice("sb-ioapic", NULL /* pCfg */, PCIAddr, true /*fGuestAddressRequired*/); H();
1734 }
1735 }
1736
1737 /*
1738 * Enable the following devices: HPET, SMC and LPC on MacOS X guests or on ICH9 chipset
1739 */
1740
1741 /*
1742 * High Precision Event Timer (HPET)
1743 */
1744 BOOL fHPETEnabled;
1745 /* Other guests may wish to use HPET too, but MacOS X not functional without it */
1746 hrc = pMachine->COMGETTER(HPETEnabled)(&fHPETEnabled); H();
1747 /* so always enable HPET in extended profile */
1748 fHPETEnabled |= fOsXGuest;
1749 /* HPET is always present on ICH9 */
1750 fHPETEnabled |= (chipsetType == ChipsetType_ICH9);
1751 if (fHPETEnabled)
1752 {
1753 InsertConfigNode(pDevices, "hpet", &pDev);
1754 InsertConfigNode(pDev, "0", &pInst);
1755 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1756 InsertConfigNode(pInst, "Config", &pCfg);
1757 InsertConfigInteger(pCfg, "ICH9", (chipsetType == ChipsetType_ICH9) ? 1 : 0); /* boolean */
1758 }
1759
1760 /*
1761 * System Management Controller (SMC)
1762 */
1763 BOOL fSmcEnabled;
1764 fSmcEnabled = fOsXGuest;
1765 if (fSmcEnabled)
1766 {
1767 InsertConfigNode(pDevices, "smc", &pDev);
1768 InsertConfigNode(pDev, "0", &pInst);
1769 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1770 InsertConfigNode(pInst, "Config", &pCfg);
1771
1772 bool fGetKeyFromRealSMC;
1773 Utf8Str strKey;
1774 vrc = getSmcDeviceKey(virtualBox, pMachine, &strKey, &fGetKeyFromRealSMC);
1775 AssertRCReturn(vrc, vrc);
1776
1777 if (!fGetKeyFromRealSMC)
1778 InsertConfigString(pCfg, "DeviceKey", strKey);
1779 InsertConfigInteger(pCfg, "GetKeyFromRealSMC", fGetKeyFromRealSMC);
1780 }
1781
1782 /*
1783 * Low Pin Count (LPC) bus
1784 */
1785 BOOL fLpcEnabled;
1786 /** @todo implement appropriate getter */
1787 fLpcEnabled = fOsXGuest || (chipsetType == ChipsetType_ICH9);
1788 if (fLpcEnabled)
1789 {
1790 InsertConfigNode(pDevices, "lpc", &pDev);
1791 InsertConfigNode(pDev, "0", &pInst);
1792 hrc = pBusMgr->assignPCIDevice("lpc", pInst); H();
1793 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1794 }
1795
1796 BOOL fShowRtc;
1797 fShowRtc = fOsXGuest || (chipsetType == ChipsetType_ICH9);
1798
1799 /*
1800 * PS/2 keyboard & mouse.
1801 */
1802 InsertConfigNode(pDevices, "pckbd", &pDev);
1803 InsertConfigNode(pDev, "0", &pInst);
1804 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1805 InsertConfigNode(pInst, "Config", &pCfg);
1806
1807 KeyboardHIDType_T aKbdHID;
1808 hrc = pMachine->COMGETTER(KeyboardHIDType)(&aKbdHID); H();
1809 if (aKbdHID != KeyboardHIDType_None)
1810 {
1811 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1812 InsertConfigString(pLunL0, "Driver", "KeyboardQueue");
1813 InsertConfigNode(pLunL0, "Config", &pCfg);
1814 InsertConfigInteger(pCfg, "QueueSize", 64);
1815
1816 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1817 InsertConfigString(pLunL1, "Driver", "MainKeyboard");
1818 }
1819
1820 PointingHIDType_T aPointingHID;
1821 hrc = pMachine->COMGETTER(PointingHIDType)(&aPointingHID); H();
1822 if (aPointingHID != PointingHIDType_None)
1823 {
1824 InsertConfigNode(pInst, "LUN#1", &pLunL0);
1825 InsertConfigString(pLunL0, "Driver", "MouseQueue");
1826 InsertConfigNode(pLunL0, "Config", &pCfg);
1827 InsertConfigInteger(pCfg, "QueueSize", 128);
1828
1829 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1830 InsertConfigString(pLunL1, "Driver", "MainMouse");
1831 }
1832
1833 /*
1834 * i8254 Programmable Interval Timer And Dummy Speaker
1835 */
1836 InsertConfigNode(pDevices, "i8254", &pDev);
1837 InsertConfigNode(pDev, "0", &pInst);
1838 InsertConfigNode(pInst, "Config", &pCfg);
1839#ifdef DEBUG
1840 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1841#endif
1842
1843 /*
1844 * i8259 Programmable Interrupt Controller.
1845 */
1846 InsertConfigNode(pDevices, "i8259", &pDev);
1847 InsertConfigNode(pDev, "0", &pInst);
1848 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1849 InsertConfigNode(pInst, "Config", &pCfg);
1850
1851 /*
1852 * Advanced Programmable Interrupt Controller.
1853 * SMP: Each CPU has a LAPIC, but we have a single device representing all LAPICs states,
1854 * thus only single insert
1855 */
1856 if (fEnableAPIC)
1857 {
1858 InsertConfigNode(pDevices, "apic", &pDev);
1859 InsertConfigNode(pDev, "0", &pInst);
1860 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1861 InsertConfigNode(pInst, "Config", &pCfg);
1862 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1863 PDMAPICMODE enmAPICMode = PDMAPICMODE_APIC;
1864 if (fEnableX2APIC)
1865 enmAPICMode = PDMAPICMODE_X2APIC;
1866 else if (!fEnableAPIC)
1867 enmAPICMode = PDMAPICMODE_NONE;
1868 InsertConfigInteger(pCfg, "Mode", enmAPICMode);
1869 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1870
1871 if (fIOAPIC)
1872 {
1873 /*
1874 * I/O Advanced Programmable Interrupt Controller.
1875 */
1876 InsertConfigNode(pDevices, "ioapic", &pDev);
1877 InsertConfigNode(pDev, "0", &pInst);
1878 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1879 InsertConfigNode(pInst, "Config", &pCfg);
1880 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1881 if (enmIommuType == IommuType_AMD)
1882 InsertConfigInteger(pCfg, "PCIAddress", uIoApicPciAddress);
1883 else if (enmIommuType == IommuType_Intel)
1884 {
1885 InsertConfigString(pCfg, "ChipType", "DMAR");
1886 InsertConfigInteger(pCfg, "PCIAddress", uIoApicPciAddress);
1887 }
1888 }
1889 }
1890
1891 /*
1892 * RTC MC146818.
1893 */
1894 InsertConfigNode(pDevices, "mc146818", &pDev);
1895 InsertConfigNode(pDev, "0", &pInst);
1896 InsertConfigNode(pInst, "Config", &pCfg);
1897 BOOL fRTCUseUTC;
1898 hrc = pMachine->COMGETTER(RTCUseUTC)(&fRTCUseUTC); H();
1899 InsertConfigInteger(pCfg, "UseUTC", fRTCUseUTC ? 1 : 0);
1900
1901 /*
1902 * VGA.
1903 */
1904 ComPtr<IGraphicsAdapter> pGraphicsAdapter;
1905 hrc = pMachine->COMGETTER(GraphicsAdapter)(pGraphicsAdapter.asOutParam()); H();
1906 GraphicsControllerType_T enmGraphicsController;
1907 hrc = pGraphicsAdapter->COMGETTER(GraphicsControllerType)(&enmGraphicsController); H();
1908 switch (enmGraphicsController)
1909 {
1910 case GraphicsControllerType_Null:
1911 break;
1912#ifdef VBOX_WITH_VMSVGA
1913 case GraphicsControllerType_VMSVGA:
1914 InsertConfigInteger(pHM, "LovelyMesaDrvWorkaround", 1); /* hits someone else logging backdoor. */
1915 InsertConfigInteger(pNEM, "LovelyMesaDrvWorkaround", 1); /* hits someone else logging backdoor. */
1916 RT_FALL_THROUGH();
1917 case GraphicsControllerType_VBoxSVGA:
1918#endif
1919 case GraphicsControllerType_VBoxVGA:
1920 vrc = i_configGraphicsController(pDevices, enmGraphicsController, pBusMgr, pMachine, pGraphicsAdapter, biosSettings,
1921 RT_BOOL(fHMEnabled));
1922 if (FAILED(vrc))
1923 return vrc;
1924 break;
1925 default:
1926 AssertMsgFailed(("Invalid graphicsController=%d\n", enmGraphicsController));
1927 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1928 N_("Invalid graphics controller type '%d'"), enmGraphicsController);
1929 }
1930
1931 /*
1932 * Firmware.
1933 */
1934 FirmwareType_T eFwType = FirmwareType_BIOS;
1935 hrc = pMachine->COMGETTER(FirmwareType)(&eFwType); H();
1936
1937#ifdef VBOX_WITH_EFI
1938 BOOL fEfiEnabled = (eFwType >= FirmwareType_EFI) && (eFwType <= FirmwareType_EFIDUAL);
1939#else
1940 BOOL fEfiEnabled = false;
1941#endif
1942 if (!fEfiEnabled)
1943 {
1944 /*
1945 * PC Bios.
1946 */
1947 InsertConfigNode(pDevices, "pcbios", &pDev);
1948 InsertConfigNode(pDev, "0", &pInst);
1949 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1950 InsertConfigNode(pInst, "Config", &pBiosCfg);
1951 InsertConfigInteger(pBiosCfg, "NumCPUs", cCpus);
1952 InsertConfigString(pBiosCfg, "HardDiskDevice", "piix3ide");
1953 InsertConfigString(pBiosCfg, "FloppyDevice", "i82078");
1954 InsertConfigInteger(pBiosCfg, "IOAPIC", fIOAPIC);
1955 InsertConfigInteger(pBiosCfg, "APIC", uFwAPIC);
1956 BOOL fPXEDebug;
1957 hrc = biosSettings->COMGETTER(PXEDebugEnabled)(&fPXEDebug); H();
1958 InsertConfigInteger(pBiosCfg, "PXEDebug", fPXEDebug);
1959 InsertConfigBytes(pBiosCfg, "UUID", &HardwareUuid,sizeof(HardwareUuid));
1960 BOOL fUuidLe;
1961 hrc = biosSettings->COMGETTER(SMBIOSUuidLittleEndian)(&fUuidLe); H();
1962 InsertConfigInteger(pBiosCfg, "UuidLe", fUuidLe);
1963 InsertConfigNode(pBiosCfg, "NetBoot", &pNetBootCfg);
1964 InsertConfigInteger(pBiosCfg, "McfgBase", uMcfgBase);
1965 InsertConfigInteger(pBiosCfg, "McfgLength", cbMcfgLength);
1966
1967 AssertMsgReturn(SchemaDefs::MaxBootPosition <= 9, ("Too many boot devices %d\n", SchemaDefs::MaxBootPosition),
1968 VERR_INVALID_PARAMETER);
1969
1970 for (ULONG pos = 1; pos <= SchemaDefs::MaxBootPosition; ++pos)
1971 {
1972 DeviceType_T enmBootDevice;
1973 hrc = pMachine->GetBootOrder(pos, &enmBootDevice); H();
1974
1975 char szParamName[] = "BootDeviceX";
1976 szParamName[sizeof(szParamName) - 2] = (char)(pos - 1 + '0');
1977
1978 const char *pszBootDevice;
1979 switch (enmBootDevice)
1980 {
1981 case DeviceType_Null:
1982 pszBootDevice = "NONE";
1983 break;
1984 case DeviceType_HardDisk:
1985 pszBootDevice = "IDE";
1986 break;
1987 case DeviceType_DVD:
1988 pszBootDevice = "DVD";
1989 break;
1990 case DeviceType_Floppy:
1991 pszBootDevice = "FLOPPY";
1992 break;
1993 case DeviceType_Network:
1994 pszBootDevice = "LAN";
1995 break;
1996 default:
1997 AssertMsgFailed(("Invalid enmBootDevice=%d\n", enmBootDevice));
1998 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1999 N_("Invalid boot device '%d'"), enmBootDevice);
2000 }
2001 InsertConfigString(pBiosCfg, szParamName, pszBootDevice);
2002 }
2003
2004 /** @todo @bugref{7145}: We might want to enable this by default for new VMs. For now,
2005 * this is required for Windows 2012 guests. */
2006 if (osTypeId == "Windows2012_64")
2007 InsertConfigInteger(pBiosCfg, "DmiExposeMemoryTable", 1); /* boolean */
2008 }
2009 else
2010 {
2011 /* Autodetect firmware type, basing on guest type */
2012 if (eFwType == FirmwareType_EFI)
2013 eFwType = fIsGuest64Bit ? FirmwareType_EFI64 : FirmwareType_EFI32;
2014 bool const f64BitEntry = eFwType == FirmwareType_EFI64;
2015
2016 Assert(eFwType == FirmwareType_EFI64 || eFwType == FirmwareType_EFI32 || eFwType == FirmwareType_EFIDUAL);
2017#ifdef VBOX_WITH_EFI_IN_DD2
2018 const char *pszEfiRomFile = eFwType == FirmwareType_EFIDUAL ? "VBoxEFIDual.fd"
2019 : eFwType == FirmwareType_EFI32 ? "VBoxEFI32.fd"
2020 : "VBoxEFI64.fd";
2021#else
2022 Utf8Str efiRomFile;
2023 vrc = findEfiRom(virtualBox, eFwType, &efiRomFile);
2024 AssertRCReturn(vrc, vrc);
2025 const char *pszEfiRomFile = efiRomFile.c_str();
2026#endif
2027
2028 /* Get boot args */
2029 Utf8Str bootArgs;
2030 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiBootArgs", &bootArgs);
2031
2032 /* Get device props */
2033 Utf8Str deviceProps;
2034 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiDeviceProps", &deviceProps);
2035
2036 /* Get NVRAM file name */
2037 Utf8Str strNvram = mptrNvramStore->i_getNonVolatileStorageFile();
2038
2039 BOOL fUuidLe;
2040 hrc = biosSettings->COMGETTER(SMBIOSUuidLittleEndian)(&fUuidLe); H();
2041
2042 /* Get graphics mode settings */
2043 uint32_t u32GraphicsMode = UINT32_MAX;
2044 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGraphicsMode", &strTmp);
2045 if (strTmp.isEmpty())
2046 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGopMode", &strTmp);
2047 if (!strTmp.isEmpty())
2048 u32GraphicsMode = strTmp.toUInt32();
2049
2050 /* Get graphics resolution settings, with some sanity checking */
2051 Utf8Str strResolution;
2052 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGraphicsResolution", &strResolution);
2053 if (!strResolution.isEmpty())
2054 {
2055 size_t pos = strResolution.find("x");
2056 if (pos != strResolution.npos)
2057 {
2058 Utf8Str strH, strV;
2059 strH.assignEx(strResolution, 0, pos);
2060 strV.assignEx(strResolution, pos+1, strResolution.length()-pos-1);
2061 uint32_t u32H = strH.toUInt32();
2062 uint32_t u32V = strV.toUInt32();
2063 if (u32H == 0 || u32V == 0)
2064 strResolution.setNull();
2065 }
2066 else
2067 strResolution.setNull();
2068 }
2069 else
2070 {
2071 uint32_t u32H = 0;
2072 uint32_t u32V = 0;
2073 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiHorizontalResolution", &strTmp);
2074 if (strTmp.isEmpty())
2075 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiUgaHorizontalResolution", &strTmp);
2076 if (!strTmp.isEmpty())
2077 u32H = strTmp.toUInt32();
2078
2079 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiVerticalResolution", &strTmp);
2080 if (strTmp.isEmpty())
2081 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiUgaVerticalResolution", &strTmp);
2082 if (!strTmp.isEmpty())
2083 u32V = strTmp.toUInt32();
2084 if (u32H != 0 && u32V != 0)
2085 strResolution = Utf8StrFmt("%ux%u", u32H, u32V);
2086 }
2087
2088 /*
2089 * EFI subtree.
2090 */
2091 InsertConfigNode(pDevices, "efi", &pDev);
2092 InsertConfigNode(pDev, "0", &pInst);
2093 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2094 InsertConfigNode(pInst, "Config", &pCfg);
2095 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
2096 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
2097 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
2098 InsertConfigString(pCfg, "EfiRom", pszEfiRomFile);
2099 InsertConfigString(pCfg, "BootArgs", bootArgs);
2100 InsertConfigString(pCfg, "DeviceProps", deviceProps);
2101 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
2102 InsertConfigInteger(pCfg, "APIC", uFwAPIC);
2103 InsertConfigBytes(pCfg, "UUID", &HardwareUuid,sizeof(HardwareUuid));
2104 InsertConfigInteger(pCfg, "UuidLe", fUuidLe);
2105 InsertConfigInteger(pCfg, "64BitEntry", f64BitEntry); /* boolean */
2106 InsertConfigString(pCfg, "NvramFile", strNvram);
2107 if (u32GraphicsMode != UINT32_MAX)
2108 InsertConfigInteger(pCfg, "GraphicsMode", u32GraphicsMode);
2109 if (!strResolution.isEmpty())
2110 InsertConfigString(pCfg, "GraphicsResolution", strResolution);
2111
2112 /* For OS X guests we'll force passing host's DMI info to the guest */
2113 if (fOsXGuest)
2114 {
2115 InsertConfigInteger(pCfg, "DmiUseHostInfo", 1);
2116 InsertConfigInteger(pCfg, "DmiExposeMemoryTable", 1);
2117 }
2118
2119 /* Attach the NVRAM storage driver. */
2120 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2121 InsertConfigString(pLunL0, "Driver", "NvramStore");
2122 }
2123
2124 /*
2125 * The USB Controllers.
2126 */
2127 com::SafeIfaceArray<IUSBController> usbCtrls;
2128 hrc = pMachine->COMGETTER(USBControllers)(ComSafeArrayAsOutParam(usbCtrls));
2129 bool fOhciPresent = false; /**< Flag whether at least one OHCI controller is present. */
2130 bool fXhciPresent = false; /**< Flag whether at least one XHCI controller is present. */
2131
2132 if (SUCCEEDED(hrc))
2133 {
2134 for (size_t i = 0; i < usbCtrls.size(); ++i)
2135 {
2136 USBControllerType_T enmCtrlType;
2137 vrc = usbCtrls[i]->COMGETTER(Type)(&enmCtrlType); H();
2138 if (enmCtrlType == USBControllerType_OHCI)
2139 {
2140 fOhciPresent = true;
2141 break;
2142 }
2143 else if (enmCtrlType == USBControllerType_XHCI)
2144 {
2145 fXhciPresent = true;
2146 break;
2147 }
2148 }
2149 }
2150 else if (hrc != E_NOTIMPL)
2151 {
2152 H();
2153 }
2154
2155 /*
2156 * Currently EHCI is only enabled when an OHCI or XHCI controller is present as well.
2157 */
2158 if (fOhciPresent || fXhciPresent)
2159 mfVMHasUsbController = true;
2160
2161 PCFGMNODE pUsbDevices = NULL; /**< Required for USB storage controller later. */
2162 if (mfVMHasUsbController)
2163 {
2164 for (size_t i = 0; i < usbCtrls.size(); ++i)
2165 {
2166 USBControllerType_T enmCtrlType;
2167 vrc = usbCtrls[i]->COMGETTER(Type)(&enmCtrlType); H();
2168
2169 if (enmCtrlType == USBControllerType_OHCI)
2170 {
2171 InsertConfigNode(pDevices, "usb-ohci", &pDev);
2172 InsertConfigNode(pDev, "0", &pInst);
2173 InsertConfigNode(pInst, "Config", &pCfg);
2174 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2175 hrc = pBusMgr->assignPCIDevice("usb-ohci", pInst); H();
2176 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2177 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
2178 InsertConfigNode(pLunL0, "Config", &pCfg);
2179
2180 /*
2181 * Attach the status driver.
2182 */
2183 i_attachStatusDriver(pInst, DeviceType_USB);
2184 }
2185#ifdef VBOX_WITH_EHCI
2186 else if (enmCtrlType == USBControllerType_EHCI)
2187 {
2188 InsertConfigNode(pDevices, "usb-ehci", &pDev);
2189 InsertConfigNode(pDev, "0", &pInst);
2190 InsertConfigNode(pInst, "Config", &pCfg);
2191 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2192 hrc = pBusMgr->assignPCIDevice("usb-ehci", pInst); H();
2193
2194 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2195 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
2196 InsertConfigNode(pLunL0, "Config", &pCfg);
2197
2198 /*
2199 * Attach the status driver.
2200 */
2201 i_attachStatusDriver(pInst, DeviceType_USB);
2202 }
2203#endif
2204 else if (enmCtrlType == USBControllerType_XHCI)
2205 {
2206 InsertConfigNode(pDevices, "usb-xhci", &pDev);
2207 InsertConfigNode(pDev, "0", &pInst);
2208 InsertConfigNode(pInst, "Config", &pCfg);
2209 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2210 hrc = pBusMgr->assignPCIDevice("usb-xhci", pInst); H();
2211
2212 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2213 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
2214 InsertConfigNode(pLunL0, "Config", &pCfg);
2215
2216 InsertConfigNode(pInst, "LUN#1", &pLunL1);
2217 InsertConfigString(pLunL1, "Driver", "VUSBRootHub");
2218 InsertConfigNode(pLunL1, "Config", &pCfg);
2219
2220 /*
2221 * Attach the status driver.
2222 */
2223 i_attachStatusDriver(pInst, DeviceType_USB, 2);
2224 }
2225 } /* for every USB controller. */
2226
2227
2228 /*
2229 * Virtual USB Devices.
2230 */
2231 InsertConfigNode(pRoot, "USB", &pUsbDevices);
2232
2233#ifdef VBOX_WITH_USB
2234 {
2235 /*
2236 * Global USB options, currently unused as we'll apply the 2.0 -> 1.1 morphing
2237 * on a per device level now.
2238 */
2239 InsertConfigNode(pUsbDevices, "USBProxy", &pCfg);
2240 InsertConfigNode(pCfg, "GlobalConfig", &pCfg);
2241 // This globally enables the 2.0 -> 1.1 device morphing of proxied devices to keep windows quiet.
2242 //InsertConfigInteger(pCfg, "Force11Device", true);
2243 // The following breaks stuff, but it makes MSDs work in vista. (I include it here so
2244 // that it's documented somewhere.) Users needing it can use:
2245 // VBoxManage setextradata "myvm" "VBoxInternal/USB/USBProxy/GlobalConfig/Force11PacketSize" 1
2246 //InsertConfigInteger(pCfg, "Force11PacketSize", true);
2247 }
2248#endif
2249
2250#ifdef VBOX_WITH_USB_CARDREADER
2251 BOOL aEmulatedUSBCardReaderEnabled = FALSE;
2252 hrc = pMachine->COMGETTER(EmulatedUSBCardReaderEnabled)(&aEmulatedUSBCardReaderEnabled); H();
2253 if (aEmulatedUSBCardReaderEnabled)
2254 {
2255 InsertConfigNode(pUsbDevices, "CardReader", &pDev);
2256 InsertConfigNode(pDev, "0", &pInst);
2257 InsertConfigNode(pInst, "Config", &pCfg);
2258
2259 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2260# ifdef VBOX_WITH_USB_CARDREADER_TEST
2261 InsertConfigString(pLunL0, "Driver", "DrvDirectCardReader");
2262 InsertConfigNode(pLunL0, "Config", &pCfg);
2263# else
2264 InsertConfigString(pLunL0, "Driver", "UsbCardReader");
2265 InsertConfigNode(pLunL0, "Config", &pCfg);
2266# endif
2267 }
2268#endif
2269
2270 /* Virtual USB Mouse/Tablet */
2271 if ( aPointingHID == PointingHIDType_USBMouse
2272 || aPointingHID == PointingHIDType_USBTablet
2273 || aPointingHID == PointingHIDType_USBMultiTouch
2274 || aPointingHID == PointingHIDType_USBMultiTouchScreenPlusPad)
2275 {
2276 InsertConfigNode(pUsbDevices, "HidMouse", &pDev);
2277 InsertConfigNode(pDev, "0", &pInst);
2278 InsertConfigNode(pInst, "Config", &pCfg);
2279
2280 if (aPointingHID == PointingHIDType_USBMouse)
2281 InsertConfigString(pCfg, "Mode", "relative");
2282 else
2283 InsertConfigString(pCfg, "Mode", "absolute");
2284 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2285 InsertConfigString(pLunL0, "Driver", "MouseQueue");
2286 InsertConfigNode(pLunL0, "Config", &pCfg);
2287 InsertConfigInteger(pCfg, "QueueSize", 128);
2288
2289 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2290 InsertConfigString(pLunL1, "Driver", "MainMouse");
2291 }
2292 if ( aPointingHID == PointingHIDType_USBMultiTouch
2293 || aPointingHID == PointingHIDType_USBMultiTouchScreenPlusPad)
2294 {
2295 InsertConfigNode(pDev, "1", &pInst);
2296 InsertConfigNode(pInst, "Config", &pCfg);
2297
2298 InsertConfigString(pCfg, "Mode", "multitouch");
2299 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2300 InsertConfigString(pLunL0, "Driver", "MouseQueue");
2301 InsertConfigNode(pLunL0, "Config", &pCfg);
2302 InsertConfigInteger(pCfg, "QueueSize", 128);
2303
2304 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2305 InsertConfigString(pLunL1, "Driver", "MainMouse");
2306 }
2307 if (aPointingHID == PointingHIDType_USBMultiTouchScreenPlusPad)
2308 {
2309 InsertConfigNode(pDev, "2", &pInst);
2310 InsertConfigNode(pInst, "Config", &pCfg);
2311
2312 InsertConfigString(pCfg, "Mode", "touchpad");
2313 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2314 InsertConfigString(pLunL0, "Driver", "MouseQueue");
2315 InsertConfigNode(pLunL0, "Config", &pCfg);
2316 InsertConfigInteger(pCfg, "QueueSize", 128);
2317
2318 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2319 InsertConfigString(pLunL1, "Driver", "MainMouse");
2320 }
2321
2322 /* Virtual USB Keyboard */
2323 if (aKbdHID == KeyboardHIDType_USBKeyboard)
2324 {
2325 InsertConfigNode(pUsbDevices, "HidKeyboard", &pDev);
2326 InsertConfigNode(pDev, "0", &pInst);
2327 InsertConfigNode(pInst, "Config", &pCfg);
2328
2329 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2330 InsertConfigString(pLunL0, "Driver", "KeyboardQueue");
2331 InsertConfigNode(pLunL0, "Config", &pCfg);
2332 InsertConfigInteger(pCfg, "QueueSize", 64);
2333
2334 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2335 InsertConfigString(pLunL1, "Driver", "MainKeyboard");
2336 }
2337 }
2338
2339 /*
2340 * Storage controllers.
2341 */
2342 com::SafeIfaceArray<IStorageController> ctrls;
2343 PCFGMNODE aCtrlNodes[StorageControllerType_VirtioSCSI + 1] = {};
2344 hrc = pMachine->COMGETTER(StorageControllers)(ComSafeArrayAsOutParam(ctrls)); H();
2345
2346 bool fFdcEnabled = false;
2347 for (size_t i = 0; i < ctrls.size(); ++i)
2348 {
2349 DeviceType_T *paLedDevType = NULL;
2350
2351 StorageControllerType_T enmCtrlType;
2352 hrc = ctrls[i]->COMGETTER(ControllerType)(&enmCtrlType); H();
2353 AssertRelease((unsigned)enmCtrlType < RT_ELEMENTS(aCtrlNodes)
2354 || enmCtrlType == StorageControllerType_USB);
2355
2356 StorageBus_T enmBus;
2357 hrc = ctrls[i]->COMGETTER(Bus)(&enmBus); H();
2358
2359 Bstr controllerName;
2360 hrc = ctrls[i]->COMGETTER(Name)(controllerName.asOutParam()); H();
2361
2362 ULONG ulInstance = 999;
2363 hrc = ctrls[i]->COMGETTER(Instance)(&ulInstance); H();
2364
2365 BOOL fUseHostIOCache;
2366 hrc = ctrls[i]->COMGETTER(UseHostIOCache)(&fUseHostIOCache); H();
2367
2368 BOOL fBootable;
2369 hrc = ctrls[i]->COMGETTER(Bootable)(&fBootable); H();
2370
2371 PCFGMNODE pCtlInst = NULL;
2372 const char *pszCtrlDev = i_storageControllerTypeToStr(enmCtrlType);
2373 if (enmCtrlType != StorageControllerType_USB)
2374 {
2375 /* /Devices/<ctrldev>/ */
2376 pDev = aCtrlNodes[enmCtrlType];
2377 if (!pDev)
2378 {
2379 InsertConfigNode(pDevices, pszCtrlDev, &pDev);
2380 aCtrlNodes[enmCtrlType] = pDev; /* IDE variants are handled in the switch */
2381 }
2382
2383 /* /Devices/<ctrldev>/<instance>/ */
2384 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pCtlInst);
2385
2386 /* Device config: /Devices/<ctrldev>/<instance>/<values> & /ditto/Config/<values> */
2387 InsertConfigInteger(pCtlInst, "Trusted", 1);
2388 InsertConfigNode(pCtlInst, "Config", &pCfg);
2389 }
2390
2391 static const char * const apszBiosConfigScsi[MAX_BIOS_LUN_COUNT] =
2392 { "ScsiLUN1", "ScsiLUN2", "ScsiLUN3", "ScsiLUN4" };
2393
2394 static const char * const apszBiosConfigSata[MAX_BIOS_LUN_COUNT] =
2395 { "SataLUN1", "SataLUN2", "SataLUN3", "SataLUN4" };
2396
2397 switch (enmCtrlType)
2398 {
2399 case StorageControllerType_LsiLogic:
2400 {
2401 hrc = pBusMgr->assignPCIDevice("lsilogic", pCtlInst); H();
2402
2403 InsertConfigInteger(pCfg, "Bootable", fBootable);
2404
2405 /* BIOS configuration values, first SCSI controller only. */
2406 if ( !pBusMgr->hasPCIDevice("lsilogic", 1)
2407 && !pBusMgr->hasPCIDevice("buslogic", 0)
2408 && !pBusMgr->hasPCIDevice("lsilogicsas", 0)
2409 && pBiosCfg)
2410 {
2411 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "lsilogicscsi");
2412 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();
2413 }
2414
2415 /* Attach the status driver */
2416 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD),
2417 16, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
2418 break;
2419 }
2420
2421 case StorageControllerType_BusLogic:
2422 {
2423 hrc = pBusMgr->assignPCIDevice("buslogic", pCtlInst); H();
2424
2425 InsertConfigInteger(pCfg, "Bootable", fBootable);
2426
2427 /* BIOS configuration values, first SCSI controller only. */
2428 if ( !pBusMgr->hasPCIDevice("lsilogic", 0)
2429 && !pBusMgr->hasPCIDevice("buslogic", 1)
2430 && !pBusMgr->hasPCIDevice("lsilogicsas", 0)
2431 && pBiosCfg)
2432 {
2433 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "buslogic");
2434 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();
2435 }
2436
2437 /* Attach the status driver */
2438 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD),
2439 16, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
2440 break;
2441 }
2442
2443 case StorageControllerType_IntelAhci:
2444 {
2445 hrc = pBusMgr->assignPCIDevice("ahci", pCtlInst); H();
2446
2447 ULONG cPorts = 0;
2448 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
2449 InsertConfigInteger(pCfg, "PortCount", cPorts);
2450 InsertConfigInteger(pCfg, "Bootable", fBootable);
2451
2452 com::SafeIfaceArray<IMediumAttachment> atts;
2453 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),
2454 ComSafeArrayAsOutParam(atts)); H();
2455
2456 /* Configure the hotpluggable flag for the port. */
2457 for (unsigned idxAtt = 0; idxAtt < atts.size(); ++idxAtt)
2458 {
2459 IMediumAttachment *pMediumAtt = atts[idxAtt];
2460
2461 LONG lPortNum = 0;
2462 hrc = pMediumAtt->COMGETTER(Port)(&lPortNum); H();
2463
2464 BOOL fHotPluggable = FALSE;
2465 hrc = pMediumAtt->COMGETTER(HotPluggable)(&fHotPluggable); H();
2466 if (SUCCEEDED(hrc))
2467 {
2468 PCFGMNODE pPortCfg;
2469 char szName[24];
2470 RTStrPrintf(szName, sizeof(szName), "Port%d", lPortNum);
2471
2472 InsertConfigNode(pCfg, szName, &pPortCfg);
2473 InsertConfigInteger(pPortCfg, "Hotpluggable", fHotPluggable ? 1 : 0);
2474 }
2475 }
2476
2477 /* BIOS configuration values, first AHCI controller only. */
2478 if ( !pBusMgr->hasPCIDevice("ahci", 1)
2479 && pBiosCfg)
2480 {
2481 InsertConfigString(pBiosCfg, "SataHardDiskDevice", "ahci");
2482 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigSata); H();
2483 }
2484
2485 /* Attach the status driver */
2486 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD),
2487 cPorts, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
2488 break;
2489 }
2490
2491 case StorageControllerType_PIIX3:
2492 case StorageControllerType_PIIX4:
2493 case StorageControllerType_ICH6:
2494 {
2495 /*
2496 * IDE (update this when the main interface changes)
2497 */
2498 hrc = pBusMgr->assignPCIDevice("piix3ide", pCtlInst); H();
2499 InsertConfigString(pCfg, "Type", controllerString(enmCtrlType));
2500
2501 /* Attach the status driver */
2502 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD),
2503 4, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
2504
2505 /* IDE flavors */
2506 aCtrlNodes[StorageControllerType_PIIX3] = pDev;
2507 aCtrlNodes[StorageControllerType_PIIX4] = pDev;
2508 aCtrlNodes[StorageControllerType_ICH6] = pDev;
2509 break;
2510 }
2511
2512 case StorageControllerType_I82078:
2513 {
2514 /*
2515 * i82078 Floppy drive controller
2516 */
2517 fFdcEnabled = true;
2518 InsertConfigInteger(pCfg, "IRQ", 6);
2519 InsertConfigInteger(pCfg, "DMA", 2);
2520 InsertConfigInteger(pCfg, "MemMapped", 0 );
2521 InsertConfigInteger(pCfg, "IOBase", 0x3f0);
2522
2523 /* Attach the status driver */
2524 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_Floppy),
2525 2, NULL, &mapMediumAttachments, pszCtrlDev, ulInstance);
2526 break;
2527 }
2528
2529 case StorageControllerType_LsiLogicSas:
2530 {
2531 hrc = pBusMgr->assignPCIDevice("lsilogicsas", pCtlInst); H();
2532
2533 InsertConfigString(pCfg, "ControllerType", "SAS1068");
2534 InsertConfigInteger(pCfg, "Bootable", fBootable);
2535
2536 /* BIOS configuration values, first SCSI controller only. */
2537 if ( !pBusMgr->hasPCIDevice("lsilogic", 0)
2538 && !pBusMgr->hasPCIDevice("buslogic", 0)
2539 && !pBusMgr->hasPCIDevice("lsilogicsas", 1)
2540 && pBiosCfg)
2541 {
2542 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "lsilogicsas");
2543 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();
2544 }
2545
2546 ULONG cPorts = 0;
2547 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
2548 InsertConfigInteger(pCfg, "NumPorts", cPorts);
2549
2550 /* Attach the status driver */
2551 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD) /*?*/,
2552 8, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
2553 break;
2554 }
2555
2556 case StorageControllerType_USB:
2557 {
2558 if (pUsbDevices)
2559 {
2560 /*
2561 * USB MSDs are handled a bit different as the device instance
2562 * doesn't match the storage controller instance but the port.
2563 */
2564 InsertConfigNode(pUsbDevices, "Msd", &pDev);
2565 pCtlInst = pDev;
2566 }
2567 else
2568 return pVMM->pfnVMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
2569 N_("There is no USB controller enabled but there\n"
2570 "is at least one USB storage device configured for this VM.\n"
2571 "To fix this problem either enable the USB controller or remove\n"
2572 "the storage device from the VM"));
2573 break;
2574 }
2575
2576 case StorageControllerType_NVMe:
2577 {
2578 hrc = pBusMgr->assignPCIDevice("nvme", pCtlInst); H();
2579
2580 ULONG cPorts = 0;
2581 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
2582 InsertConfigInteger(pCfg, "NamespacesMax", cPorts);
2583
2584 /* Attach the status driver */
2585 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk),
2586 cPorts, NULL, &mapMediumAttachments, pszCtrlDev, ulInstance);
2587 break;
2588 }
2589
2590 case StorageControllerType_VirtioSCSI:
2591 {
2592 hrc = pBusMgr->assignPCIDevice("virtio-scsi", pCtlInst); H();
2593
2594 ULONG cPorts = 0;
2595 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
2596 InsertConfigInteger(pCfg, "NumTargets", cPorts);
2597 InsertConfigInteger(pCfg, "Bootable", fBootable);
2598
2599 /* Attach the status driver */
2600 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD) /*?*/,
2601 cPorts, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
2602 break;
2603 }
2604
2605 default:
2606 AssertLogRelMsgFailedReturn(("invalid storage controller type: %d\n", enmCtrlType), VERR_MAIN_CONFIG_CONSTRUCTOR_IPE);
2607 }
2608
2609 /* Attach the media to the storage controllers. */
2610 com::SafeIfaceArray<IMediumAttachment> atts;
2611 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),
2612 ComSafeArrayAsOutParam(atts)); H();
2613
2614 /* Builtin I/O cache - per device setting. */
2615 BOOL fBuiltinIOCache = true;
2616 hrc = pMachine->COMGETTER(IOCacheEnabled)(&fBuiltinIOCache); H();
2617
2618 bool fInsertDiskIntegrityDrv = false;
2619 Bstr strDiskIntegrityFlag;
2620 hrc = pMachine->GetExtraData(Bstr("VBoxInternal2/EnableDiskIntegrityDriver").raw(),
2621 strDiskIntegrityFlag.asOutParam());
2622 if ( hrc == S_OK
2623 && strDiskIntegrityFlag == "1")
2624 fInsertDiskIntegrityDrv = true;
2625
2626 for (size_t j = 0; j < atts.size(); ++j)
2627 {
2628 IMediumAttachment *pMediumAtt = atts[j];
2629 vrc = i_configMediumAttachment(pszCtrlDev,
2630 ulInstance,
2631 enmBus,
2632 !!fUseHostIOCache,
2633 enmCtrlType == StorageControllerType_NVMe ? false : !!fBuiltinIOCache,
2634 fInsertDiskIntegrityDrv,
2635 false /* fSetupMerge */,
2636 0 /* uMergeSource */,
2637 0 /* uMergeTarget */,
2638 pMediumAtt,
2639 mMachineState,
2640 NULL /* phrc */,
2641 false /* fAttachDetach */,
2642 false /* fForceUnmount */,
2643 false /* fHotplug */,
2644 pUVM,
2645 pVMM,
2646 paLedDevType,
2647 NULL /* ppLunL0 */);
2648 if (RT_FAILURE(vrc))
2649 return vrc;
2650 }
2651 H();
2652 }
2653 H();
2654
2655 /*
2656 * Network adapters
2657 */
2658#ifdef VMWARE_NET_IN_SLOT_11
2659 bool fSwapSlots3and11 = false;
2660#endif
2661 PCFGMNODE pDevPCNet = NULL; /* PCNet-type devices */
2662 InsertConfigNode(pDevices, "pcnet", &pDevPCNet);
2663#ifdef VBOX_WITH_E1000
2664 PCFGMNODE pDevE1000 = NULL; /* E1000-type devices */
2665 InsertConfigNode(pDevices, "e1000", &pDevE1000);
2666#endif
2667#ifdef VBOX_WITH_VIRTIO
2668 PCFGMNODE pDevVirtioNet = NULL; /* Virtio network devices */
2669 InsertConfigNode(pDevices, "virtio-net", &pDevVirtioNet);
2670#endif /* VBOX_WITH_VIRTIO */
2671 PCFGMNODE pDevDP8390 = NULL; /* DP8390-type devices */
2672 InsertConfigNode(pDevices, "dp8390", &pDevDP8390);
2673 PCFGMNODE pDev3C501 = NULL; /* EtherLink-type devices */
2674 InsertConfigNode(pDevices, "3c501", &pDev3C501);
2675
2676 std::list<BootNic> llBootNics;
2677 for (ULONG uInstance = 0; uInstance < maxNetworkAdapters; ++uInstance)
2678 {
2679 ComPtr<INetworkAdapter> networkAdapter;
2680 hrc = pMachine->GetNetworkAdapter(uInstance, networkAdapter.asOutParam()); H();
2681 BOOL fEnabledNetAdapter = FALSE;
2682 hrc = networkAdapter->COMGETTER(Enabled)(&fEnabledNetAdapter); H();
2683 if (!fEnabledNetAdapter)
2684 continue;
2685
2686 /*
2687 * The virtual hardware type. Create appropriate device first.
2688 */
2689 const char *pszAdapterName = "pcnet";
2690 NetworkAdapterType_T adapterType;
2691 hrc = networkAdapter->COMGETTER(AdapterType)(&adapterType); H();
2692 switch (adapterType)
2693 {
2694 case NetworkAdapterType_Am79C970A:
2695 case NetworkAdapterType_Am79C973:
2696 case NetworkAdapterType_Am79C960:
2697 pDev = pDevPCNet;
2698 break;
2699#ifdef VBOX_WITH_E1000
2700 case NetworkAdapterType_I82540EM:
2701 case NetworkAdapterType_I82543GC:
2702 case NetworkAdapterType_I82545EM:
2703 pDev = pDevE1000;
2704 pszAdapterName = "e1000";
2705 break;
2706#endif
2707#ifdef VBOX_WITH_VIRTIO
2708 case NetworkAdapterType_Virtio:
2709 pDev = pDevVirtioNet;
2710 pszAdapterName = "virtio-net";
2711 break;
2712#endif /* VBOX_WITH_VIRTIO */
2713 case NetworkAdapterType_NE1000:
2714 case NetworkAdapterType_NE2000:
2715 case NetworkAdapterType_WD8003:
2716 case NetworkAdapterType_WD8013:
2717 case NetworkAdapterType_ELNK2:
2718 pDev = pDevDP8390;
2719 break;
2720 case NetworkAdapterType_ELNK1:
2721 pDev = pDev3C501;
2722 break;
2723 default:
2724 AssertMsgFailed(("Invalid network adapter type '%d' for slot '%d'", adapterType, uInstance));
2725 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
2726 N_("Invalid network adapter type '%d' for slot '%d'"), adapterType, uInstance);
2727 }
2728
2729 InsertConfigNode(pDev, Utf8StrFmt("%u", uInstance).c_str(), &pInst);
2730 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2731 /* the first network card gets the PCI ID 3, the next 3 gets 8..10,
2732 * next 4 get 16..19. */
2733 int iPCIDeviceNo;
2734 switch (uInstance)
2735 {
2736 case 0:
2737 iPCIDeviceNo = 3;
2738 break;
2739 case 1: case 2: case 3:
2740 iPCIDeviceNo = uInstance - 1 + 8;
2741 break;
2742 case 4: case 5: case 6: case 7:
2743 iPCIDeviceNo = uInstance - 4 + 16;
2744 break;
2745 default:
2746 /* auto assignment */
2747 iPCIDeviceNo = -1;
2748 break;
2749 }
2750#ifdef VMWARE_NET_IN_SLOT_11
2751 /*
2752 * Dirty hack for PCI slot compatibility with VMWare,
2753 * it assigns slot 0x11 to the first network controller.
2754 */
2755 if (iPCIDeviceNo == 3 && adapterType == NetworkAdapterType_I82545EM)
2756 {
2757 iPCIDeviceNo = 0x11;
2758 fSwapSlots3and11 = true;
2759 }
2760 else if (iPCIDeviceNo == 0x11 && fSwapSlots3and11)
2761 iPCIDeviceNo = 3;
2762#endif
2763 PCIBusAddress PCIAddr = PCIBusAddress(0, iPCIDeviceNo, 0);
2764 hrc = pBusMgr->assignPCIDevice(pszAdapterName, pInst, PCIAddr); H();
2765
2766 InsertConfigNode(pInst, "Config", &pCfg);
2767#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE /* not safe here yet. */ /** @todo Make PCNet ring-0 safe on 32-bit mac kernels! */
2768 if (pDev == pDevPCNet)
2769 InsertConfigInteger(pCfg, "R0Enabled", false);
2770#endif
2771 /*
2772 * Collect information needed for network booting and add it to the list.
2773 */
2774 BootNic nic;
2775
2776 nic.mInstance = uInstance;
2777 /* Could be updated by reference, if auto assigned */
2778 nic.mPCIAddress = PCIAddr;
2779
2780 hrc = networkAdapter->COMGETTER(BootPriority)(&nic.mBootPrio); H();
2781
2782 llBootNics.push_back(nic);
2783
2784 /*
2785 * The virtual hardware type. PCNet supports three types, E1000 three,
2786 * but VirtIO only one.
2787 */
2788 switch (adapterType)
2789 {
2790 case NetworkAdapterType_Am79C970A:
2791 InsertConfigString(pCfg, "ChipType", "Am79C970A");
2792 break;
2793 case NetworkAdapterType_Am79C973:
2794 InsertConfigString(pCfg, "ChipType", "Am79C973");
2795 break;
2796 case NetworkAdapterType_Am79C960:
2797 InsertConfigString(pCfg, "ChipType", "Am79C960");
2798 break;
2799 case NetworkAdapterType_I82540EM:
2800 InsertConfigInteger(pCfg, "AdapterType", 0);
2801 break;
2802 case NetworkAdapterType_I82543GC:
2803 InsertConfigInteger(pCfg, "AdapterType", 1);
2804 break;
2805 case NetworkAdapterType_I82545EM:
2806 InsertConfigInteger(pCfg, "AdapterType", 2);
2807 break;
2808 case NetworkAdapterType_Virtio:
2809 break;
2810 case NetworkAdapterType_NE1000:
2811 InsertConfigString(pCfg, "DeviceType", "NE1000");
2812 break;
2813 case NetworkAdapterType_NE2000:
2814 InsertConfigString(pCfg, "DeviceType", "NE2000");
2815 break;
2816 case NetworkAdapterType_WD8003:
2817 InsertConfigString(pCfg, "DeviceType", "WD8003");
2818 break;
2819 case NetworkAdapterType_WD8013:
2820 InsertConfigString(pCfg, "DeviceType", "WD8013");
2821 break;
2822 case NetworkAdapterType_ELNK2:
2823 InsertConfigString(pCfg, "DeviceType", "3C503");
2824 break;
2825 case NetworkAdapterType_ELNK1:
2826 break;
2827 case NetworkAdapterType_Null: AssertFailedBreak(); /* (compiler warnings) */
2828#ifdef VBOX_WITH_XPCOM_CPP_ENUM_HACK
2829 case NetworkAdapterType_32BitHack: AssertFailedBreak(); /* (compiler warnings) */
2830#endif
2831 }
2832
2833 /*
2834 * Get the MAC address and convert it to binary representation
2835 */
2836 Bstr macAddr;
2837 hrc = networkAdapter->COMGETTER(MACAddress)(macAddr.asOutParam()); H();
2838 Assert(!macAddr.isEmpty());
2839 Utf8Str macAddrUtf8 = macAddr;
2840#ifdef VBOX_WITH_CLOUD_NET
2841 NetworkAttachmentType_T eAttachmentType;
2842 hrc = networkAdapter->COMGETTER(AttachmentType)(&eAttachmentType); H();
2843 if (eAttachmentType == NetworkAttachmentType_Cloud)
2844 {
2845 mGateway.setLocalMacAddress(macAddrUtf8);
2846 /* We'll insert cloud MAC later, when it becomes known. */
2847 }
2848 else
2849 {
2850#endif
2851 char *macStr = (char*)macAddrUtf8.c_str();
2852 Assert(strlen(macStr) == 12);
2853 RTMAC Mac;
2854 RT_ZERO(Mac);
2855 char *pMac = (char*)&Mac;
2856 for (uint32_t i = 0; i < 6; ++i)
2857 {
2858 int c1 = *macStr++ - '0';
2859 if (c1 > 9)
2860 c1 -= 7;
2861 int c2 = *macStr++ - '0';
2862 if (c2 > 9)
2863 c2 -= 7;
2864 *pMac++ = (char)(((c1 & 0x0f) << 4) | (c2 & 0x0f));
2865 }
2866 InsertConfigBytes(pCfg, "MAC", &Mac, sizeof(Mac));
2867#ifdef VBOX_WITH_CLOUD_NET
2868 }
2869#endif
2870 /*
2871 * Check if the cable is supposed to be unplugged
2872 */
2873 BOOL fCableConnected;
2874 hrc = networkAdapter->COMGETTER(CableConnected)(&fCableConnected); H();
2875 InsertConfigInteger(pCfg, "CableConnected", fCableConnected ? 1 : 0);
2876
2877 /*
2878 * Line speed to report from custom drivers
2879 */
2880 ULONG ulLineSpeed;
2881 hrc = networkAdapter->COMGETTER(LineSpeed)(&ulLineSpeed); H();
2882 InsertConfigInteger(pCfg, "LineSpeed", ulLineSpeed);
2883
2884 /*
2885 * Attach the status driver.
2886 */
2887 i_attachStatusDriver(pInst, DeviceType_Network);
2888
2889 /*
2890 * Configure the network card now
2891 */
2892 bool fIgnoreConnectFailure = mMachineState == MachineState_Restoring;
2893 vrc = i_configNetwork(pszAdapterName,
2894 uInstance,
2895 0,
2896 networkAdapter,
2897 pCfg,
2898 pLunL0,
2899 pInst,
2900 false /*fAttachDetach*/,
2901 fIgnoreConnectFailure,
2902 pUVM,
2903 pVMM);
2904 if (RT_FAILURE(vrc))
2905 return vrc;
2906 }
2907
2908 /*
2909 * Build network boot information and transfer it to the BIOS.
2910 */
2911 if (pNetBootCfg && !llBootNics.empty()) /* NetBoot node doesn't exist for EFI! */
2912 {
2913 llBootNics.sort(); /* Sort the list by boot priority. */
2914
2915 char achBootIdx[] = "0";
2916 unsigned uBootIdx = 0;
2917
2918 for (std::list<BootNic>::iterator it = llBootNics.begin(); it != llBootNics.end(); ++it)
2919 {
2920 /* A NIC with priority 0 is only used if it's first in the list. */
2921 if (it->mBootPrio == 0 && uBootIdx != 0)
2922 break;
2923
2924 PCFGMNODE pNetBtDevCfg;
2925 achBootIdx[0] = (char)('0' + uBootIdx++); /* Boot device order. */
2926 InsertConfigNode(pNetBootCfg, achBootIdx, &pNetBtDevCfg);
2927 InsertConfigInteger(pNetBtDevCfg, "NIC", it->mInstance);
2928 InsertConfigInteger(pNetBtDevCfg, "PCIBusNo", it->mPCIAddress.miBus);
2929 InsertConfigInteger(pNetBtDevCfg, "PCIDeviceNo", it->mPCIAddress.miDevice);
2930 InsertConfigInteger(pNetBtDevCfg, "PCIFunctionNo", it->mPCIAddress.miFn);
2931 }
2932 }
2933
2934 /*
2935 * Serial (UART) Ports
2936 */
2937 /* serial enabled mask to be passed to dev ACPI */
2938 uint16_t auSerialIoPortBase[SchemaDefs::SerialPortCount] = {0};
2939 uint8_t auSerialIrq[SchemaDefs::SerialPortCount] = {0};
2940 InsertConfigNode(pDevices, "serial", &pDev);
2941 for (ULONG ulInstance = 0; ulInstance < SchemaDefs::SerialPortCount; ++ulInstance)
2942 {
2943 ComPtr<ISerialPort> serialPort;
2944 hrc = pMachine->GetSerialPort(ulInstance, serialPort.asOutParam()); H();
2945 BOOL fEnabledSerPort = FALSE;
2946 if (serialPort)
2947 {
2948 hrc = serialPort->COMGETTER(Enabled)(&fEnabledSerPort); H();
2949 }
2950 if (!fEnabledSerPort)
2951 {
2952 m_aeSerialPortMode[ulInstance] = PortMode_Disconnected;
2953 continue;
2954 }
2955
2956 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
2957 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2958 InsertConfigNode(pInst, "Config", &pCfg);
2959
2960 ULONG ulIRQ;
2961 hrc = serialPort->COMGETTER(IRQ)(&ulIRQ); H();
2962 InsertConfigInteger(pCfg, "IRQ", ulIRQ);
2963 auSerialIrq[ulInstance] = (uint8_t)ulIRQ;
2964
2965 ULONG ulIOBase;
2966 hrc = serialPort->COMGETTER(IOBase)(&ulIOBase); H();
2967 InsertConfigInteger(pCfg, "IOBase", ulIOBase);
2968 auSerialIoPortBase[ulInstance] = (uint16_t)ulIOBase;
2969
2970 BOOL fServer;
2971 hrc = serialPort->COMGETTER(Server)(&fServer); H();
2972 hrc = serialPort->COMGETTER(Path)(bstr.asOutParam()); H();
2973 UartType_T eUartType;
2974 const char *pszUartType;
2975 hrc = serialPort->COMGETTER(UartType)(&eUartType); H();
2976 switch (eUartType)
2977 {
2978 case UartType_U16450: pszUartType = "16450"; break;
2979 case UartType_U16750: pszUartType = "16750"; break;
2980 default: AssertFailed(); RT_FALL_THRU();
2981 case UartType_U16550A: pszUartType = "16550A"; break;
2982 }
2983 InsertConfigString(pCfg, "UartType", pszUartType);
2984
2985 PortMode_T eHostMode;
2986 hrc = serialPort->COMGETTER(HostMode)(&eHostMode); H();
2987
2988 m_aeSerialPortMode[ulInstance] = eHostMode;
2989 if (eHostMode != PortMode_Disconnected)
2990 {
2991 vrc = i_configSerialPort(pInst, eHostMode, Utf8Str(bstr).c_str(), RT_BOOL(fServer));
2992 if (RT_FAILURE(vrc))
2993 return vrc;
2994 }
2995 }
2996
2997 /*
2998 * Parallel (LPT) Ports
2999 */
3000 /* parallel enabled mask to be passed to dev ACPI */
3001 uint16_t auParallelIoPortBase[SchemaDefs::ParallelPortCount] = {0};
3002 uint8_t auParallelIrq[SchemaDefs::ParallelPortCount] = {0};
3003 InsertConfigNode(pDevices, "parallel", &pDev);
3004 for (ULONG ulInstance = 0; ulInstance < SchemaDefs::ParallelPortCount; ++ulInstance)
3005 {
3006 ComPtr<IParallelPort> parallelPort;
3007 hrc = pMachine->GetParallelPort(ulInstance, parallelPort.asOutParam()); H();
3008 BOOL fEnabledParPort = FALSE;
3009 if (parallelPort)
3010 {
3011 hrc = parallelPort->COMGETTER(Enabled)(&fEnabledParPort); H();
3012 }
3013 if (!fEnabledParPort)
3014 continue;
3015
3016 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
3017 InsertConfigNode(pInst, "Config", &pCfg);
3018
3019 ULONG ulIRQ;
3020 hrc = parallelPort->COMGETTER(IRQ)(&ulIRQ); H();
3021 InsertConfigInteger(pCfg, "IRQ", ulIRQ);
3022 auParallelIrq[ulInstance] = (uint8_t)ulIRQ;
3023 ULONG ulIOBase;
3024 hrc = parallelPort->COMGETTER(IOBase)(&ulIOBase); H();
3025 InsertConfigInteger(pCfg, "IOBase", ulIOBase);
3026 auParallelIoPortBase[ulInstance] = (uint16_t)ulIOBase;
3027
3028 hrc = parallelPort->COMGETTER(Path)(bstr.asOutParam()); H();
3029 if (!bstr.isEmpty())
3030 {
3031 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3032 InsertConfigString(pLunL0, "Driver", "HostParallel");
3033 InsertConfigNode(pLunL0, "Config", &pLunL1);
3034 InsertConfigString(pLunL1, "DevicePath", bstr);
3035 }
3036 }
3037
3038 /*
3039 * VMM Device
3040 */
3041 InsertConfigNode(pDevices, "VMMDev", &pDev);
3042 InsertConfigNode(pDev, "0", &pInst);
3043 InsertConfigNode(pInst, "Config", &pCfg);
3044 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3045 hrc = pBusMgr->assignPCIDevice("VMMDev", pInst); H();
3046
3047 Bstr hwVersion;
3048 hrc = pMachine->COMGETTER(HardwareVersion)(hwVersion.asOutParam()); H();
3049 if (hwVersion.compare(Bstr("1").raw()) == 0) /* <= 2.0.x */
3050 InsertConfigInteger(pCfg, "HeapEnabled", 0);
3051 Bstr snapshotFolder;
3052 hrc = pMachine->COMGETTER(SnapshotFolder)(snapshotFolder.asOutParam()); H();
3053 InsertConfigString(pCfg, "GuestCoreDumpDir", snapshotFolder);
3054
3055 /* the VMM device's Main driver */
3056 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3057 InsertConfigString(pLunL0, "Driver", "HGCM");
3058 InsertConfigNode(pLunL0, "Config", &pCfg);
3059
3060 /*
3061 * Attach the status driver.
3062 */
3063 i_attachStatusDriver(pInst, DeviceType_SharedFolder);
3064
3065 /*
3066 * Audio configuration.
3067 */
3068
3069 /*
3070 * AC'97 ICH / SoundBlaster16 audio / Intel HD Audio.
3071 */
3072 ComPtr<IAudioSettings> audioSettings;
3073 hrc = pMachine->COMGETTER(AudioSettings)(audioSettings.asOutParam()); H();
3074
3075 BOOL fAudioEnabled = FALSE;
3076 ComPtr<IAudioAdapter> audioAdapter;
3077 hrc = audioSettings->COMGETTER(Adapter)(audioAdapter.asOutParam()); H();
3078 if (audioAdapter)
3079 {
3080 hrc = audioAdapter->COMGETTER(Enabled)(&fAudioEnabled); H();
3081 }
3082
3083 if (fAudioEnabled)
3084 {
3085 AudioControllerType_T enmAudioController;
3086 hrc = audioAdapter->COMGETTER(AudioController)(&enmAudioController); H();
3087 AudioCodecType_T enmAudioCodec;
3088 hrc = audioAdapter->COMGETTER(AudioCodec)(&enmAudioCodec); H();
3089
3090 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/Device/TimerHz", &strTmp);
3091 const uint64_t uTimerHz = strTmp.toUInt64();
3092
3093 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/Device/BufSizeInMs", &strTmp);
3094 const uint64_t uBufSizeInMs = strTmp.toUInt64();
3095
3096 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/Device/BufSizeOutMs", &strTmp);
3097 const uint64_t uBufSizeOutMs = strTmp.toUInt64();
3098
3099 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/Debug/Enabled", &strTmp);
3100 const bool fDebugEnabled = strTmp.equalsIgnoreCase("true") || strTmp.equalsIgnoreCase("1");
3101
3102 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/Debug/Level", &strTmp);
3103 const uint32_t uDebugLevel = strTmp.toUInt32();
3104
3105 Utf8Str strDebugPathOut;
3106 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/Debug/PathOut", &strDebugPathOut);
3107
3108#ifdef VBOX_WITH_AUDIO_VALIDATIONKIT
3109 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/VaKit/Enabled", &strTmp); /* Deprecated; do not use! */
3110 if (strTmp.isEmpty())
3111 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/ValKit/Enabled", &strTmp);
3112 /* Whether the Validation Kit audio backend runs as the primary backend.
3113 * Can also be used with VBox release builds. */
3114 const bool fValKitEnabled = strTmp.equalsIgnoreCase("true") || strTmp.equalsIgnoreCase("1");
3115#endif
3116 /** @todo Implement an audio device class, similar to the audio backend class, to construct the common stuff
3117 * without duplicating (more) code. */
3118
3119 const char *pszAudioDevice;
3120 switch (enmAudioController)
3121 {
3122 case AudioControllerType_AC97:
3123 {
3124 /* ICH AC'97. */
3125 pszAudioDevice = "ichac97";
3126
3127 InsertConfigNode(pDevices, pszAudioDevice, &pDev);
3128 InsertConfigNode(pDev, "0", &pInst);
3129 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3130 hrc = pBusMgr->assignPCIDevice(pszAudioDevice, pInst); H();
3131 InsertConfigNode(pInst, "Config", &pCfg);
3132 switch (enmAudioCodec)
3133 {
3134 case AudioCodecType_STAC9700:
3135 InsertConfigString(pCfg, "Codec", "STAC9700");
3136 break;
3137 case AudioCodecType_AD1980:
3138 InsertConfigString(pCfg, "Codec", "AD1980");
3139 break;
3140 default: AssertFailedBreak();
3141 }
3142 if (uTimerHz)
3143 InsertConfigInteger(pCfg, "TimerHz", uTimerHz);
3144 if (uBufSizeInMs)
3145 InsertConfigInteger(pCfg, "BufSizeInMs", uBufSizeInMs);
3146 if (uBufSizeOutMs)
3147 InsertConfigInteger(pCfg, "BufSizeOutMs", uBufSizeOutMs);
3148 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
3149 if (strDebugPathOut.isNotEmpty())
3150 InsertConfigString(pCfg, "DebugPathOut", strDebugPathOut);
3151 break;
3152 }
3153 case AudioControllerType_SB16:
3154 {
3155 /* Legacy SoundBlaster16. */
3156 pszAudioDevice = "sb16";
3157
3158 InsertConfigNode(pDevices, pszAudioDevice, &pDev);
3159 InsertConfigNode(pDev, "0", &pInst);
3160 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3161 InsertConfigNode(pInst, "Config", &pCfg);
3162 InsertConfigInteger(pCfg, "IRQ", 5);
3163 InsertConfigInteger(pCfg, "DMA", 1);
3164 InsertConfigInteger(pCfg, "DMA16", 5);
3165 InsertConfigInteger(pCfg, "Port", 0x220);
3166 InsertConfigInteger(pCfg, "Version", 0x0405);
3167 if (uTimerHz)
3168 InsertConfigInteger(pCfg, "TimerHz", uTimerHz);
3169 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
3170 if (strDebugPathOut.isNotEmpty())
3171 InsertConfigString(pCfg, "DebugPathOut", strDebugPathOut);
3172 break;
3173 }
3174 case AudioControllerType_HDA:
3175 {
3176 /* Intel HD Audio. */
3177 pszAudioDevice = "hda";
3178
3179 InsertConfigNode(pDevices, pszAudioDevice, &pDev);
3180 InsertConfigNode(pDev, "0", &pInst);
3181 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3182 hrc = pBusMgr->assignPCIDevice(pszAudioDevice, pInst); H();
3183 InsertConfigNode(pInst, "Config", &pCfg);
3184 if (uBufSizeInMs)
3185 InsertConfigInteger(pCfg, "BufSizeInMs", uBufSizeInMs);
3186 if (uBufSizeOutMs)
3187 InsertConfigInteger(pCfg, "BufSizeOutMs", uBufSizeOutMs);
3188 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
3189 if (strDebugPathOut.isNotEmpty())
3190 InsertConfigString(pCfg, "DebugPathOut", strDebugPathOut);
3191
3192 /* macOS guests uses a different HDA variant to make 10.14+ (or maybe 10.13?) recognize the device. */
3193 if (fOsXGuest)
3194 InsertConfigString(pCfg, "DeviceName", "Intel Sunrise Point");
3195 break;
3196 }
3197 default:
3198 pszAudioDevice = "oops";
3199 AssertFailedBreak();
3200 }
3201
3202 PCFGMNODE pCfgAudioAdapter = NULL;
3203 InsertConfigNode(pInst, "AudioConfig", &pCfgAudioAdapter);
3204 SafeArray<BSTR> audioProps;
3205 hrc = audioAdapter->COMGETTER(PropertiesList)(ComSafeArrayAsOutParam(audioProps)); H();
3206
3207 std::list<Utf8Str> audioPropertyNamesList;
3208 for (size_t i = 0; i < audioProps.size(); ++i)
3209 {
3210 Bstr bstrValue;
3211 audioPropertyNamesList.push_back(Utf8Str(audioProps[i]));
3212 hrc = audioAdapter->GetProperty(audioProps[i], bstrValue.asOutParam());
3213 Utf8Str strKey(audioProps[i]);
3214 InsertConfigString(pCfgAudioAdapter, strKey.c_str(), bstrValue);
3215 }
3216
3217 /*
3218 * The audio driver.
3219 */
3220 const char *pszAudioDriver = NULL;
3221#ifdef VBOX_WITH_AUDIO_VALIDATIONKIT
3222 if (fValKitEnabled)
3223 {
3224 pszAudioDriver = "ValidationKitAudio";
3225 LogRel(("Audio: ValidationKit driver active\n"));
3226 }
3227#endif
3228 /* If nothing else was selected before, ask the API. */
3229 if (pszAudioDriver == NULL)
3230 {
3231 AudioDriverType_T enmAudioDriver;
3232 hrc = audioAdapter->COMGETTER(AudioDriver)(&enmAudioDriver); H();
3233
3234 /* The "Default" audio driver needs special treatment, as we need to figure out which driver to use
3235 * by default on the current platform. */
3236 bool const fUseDefaultDrv = enmAudioDriver == AudioDriverType_Default;
3237
3238 AudioDriverType_T const enmDefaultAudioDriver = settings::MachineConfigFile::getHostDefaultAudioDriver();
3239
3240 if (fUseDefaultDrv)
3241 {
3242 enmAudioDriver = enmDefaultAudioDriver;
3243 if (enmAudioDriver == AudioDriverType_Null)
3244 LogRel(("Audio: Warning: No default driver detected for current platform -- defaulting to Null audio backend\n"));
3245 }
3246
3247 switch (enmAudioDriver)
3248 {
3249 case AudioDriverType_Default: /* Can't happen, but handle it anyway. */
3250 RT_FALL_THROUGH();
3251 case AudioDriverType_Null:
3252 pszAudioDriver = "NullAudio";
3253 break;
3254#ifdef RT_OS_WINDOWS
3255# ifdef VBOX_WITH_WINMM
3256 case AudioDriverType_WinMM:
3257# error "Port WinMM audio backend!" /** @todo Still needed? */
3258 break;
3259# endif
3260 case AudioDriverType_DirectSound:
3261 /* Use the Windows Audio Session (WAS) API rather than Direct Sound on Windows
3262 versions we've tested it on (currently W7+). Since Vista, Direct Sound has
3263 been emulated on top of WAS according to the docs, so better use WAS directly.
3264
3265 Set extradata value "VBoxInternal2/Audio/WindowsDrv" "dsound" to no use WasAPI.
3266
3267 Keep this hack for backwards compatibility (introduced < 7.0).
3268 */
3269 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/WindowsDrv", &strTmp); H();
3270 if ( enmDefaultAudioDriver == AudioDriverType_WAS
3271 && ( strTmp.isEmpty()
3272 || strTmp.equalsIgnoreCase("was")
3273 || strTmp.equalsIgnoreCase("wasapi")) )
3274 {
3275 /* Nothing to do here, fall through to WAS driver. */
3276 }
3277 else
3278 {
3279 pszAudioDriver = "DSoundAudio";
3280 break;
3281 }
3282 RT_FALL_THROUGH();
3283 case AudioDriverType_WAS:
3284 if (enmDefaultAudioDriver == AudioDriverType_WAS) /* WAS supported? */
3285 pszAudioDriver = "HostAudioWas";
3286 else if (enmDefaultAudioDriver == AudioDriverType_DirectSound)
3287 {
3288 LogRel(("Audio: Warning: Windows Audio Session (WAS) not supported, defaulting to DirectSound backend\n"));
3289 pszAudioDriver = "DSoundAudio";
3290 }
3291 break;
3292#endif /* RT_OS_WINDOWS */
3293#ifdef RT_OS_SOLARIS
3294 case AudioDriverType_SolAudio:
3295 /* Should not happen, as the Solaris Audio backend is not around anymore.
3296 * Remove this sometime later. */
3297 LogRel(("Audio: Warning: Solaris Audio is deprecated, please switch to OSS!\n"));
3298 LogRel(("Audio: Automatically setting host audio backend to OSS\n"));
3299
3300 /* Manually set backend to OSS for now. */
3301 pszAudioDriver = "OSSAudio";
3302 break;
3303#endif
3304#ifdef VBOX_WITH_AUDIO_OSS
3305 case AudioDriverType_OSS:
3306 pszAudioDriver = "OSSAudio";
3307 break;
3308#endif
3309#ifdef VBOX_WITH_AUDIO_ALSA
3310 case AudioDriverType_ALSA:
3311 pszAudioDriver = "ALSAAudio";
3312 break;
3313#endif
3314#ifdef VBOX_WITH_AUDIO_PULSE
3315 case AudioDriverType_Pulse:
3316 pszAudioDriver = "PulseAudio";
3317 break;
3318#endif
3319#ifdef RT_OS_DARWIN
3320 case AudioDriverType_CoreAudio:
3321 pszAudioDriver = "CoreAudio";
3322 break;
3323#endif
3324 default:
3325 pszAudioDriver = "oops";
3326 AssertFailedBreak();
3327 }
3328
3329 if (fUseDefaultDrv)
3330 LogRel(("Audio: Detected default audio driver type is '%s'\n", pszAudioDriver));
3331 }
3332
3333 BOOL fAudioEnabledIn = FALSE;
3334 hrc = audioAdapter->COMGETTER(EnabledIn)(&fAudioEnabledIn); H();
3335 BOOL fAudioEnabledOut = FALSE;
3336 hrc = audioAdapter->COMGETTER(EnabledOut)(&fAudioEnabledOut); H();
3337
3338 unsigned idxAudioLun = 0;
3339
3340 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", idxAudioLun);
3341 i_configAudioDriver(virtualBox, pMachine, pLunL0, pszAudioDriver, !!fAudioEnabledIn, !!fAudioEnabledOut);
3342 idxAudioLun++;
3343
3344#ifdef VBOX_WITH_AUDIO_VRDE
3345 /* Insert dummy audio driver to have the LUN configured. */
3346 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", idxAudioLun);
3347 InsertConfigString(pLunL0, "Driver", "AUDIO");
3348 {
3349 AudioDriverCfg DrvCfgVRDE(pszAudioDevice, 0 /* Instance */, idxAudioLun, "AudioVRDE",
3350 !!fAudioEnabledIn, !!fAudioEnabledOut);
3351 vrc = mAudioVRDE->InitializeConfig(&DrvCfgVRDE);
3352 AssertRCStmt(vrc, throw ConfigError(__FUNCTION__, vrc, "mAudioVRDE->InitializeConfig failed"));
3353 }
3354 idxAudioLun++;
3355#endif
3356
3357#ifdef VBOX_WITH_AUDIO_RECORDING
3358 /* Insert dummy audio driver to have the LUN configured. */
3359 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", idxAudioLun);
3360 InsertConfigString(pLunL0, "Driver", "AUDIO");
3361 {
3362 AudioDriverCfg DrvCfgVideoRec(pszAudioDevice, 0 /* Instance */, idxAudioLun, "AudioVideoRec",
3363 false /*a_fEnabledIn*/, true /*a_fEnabledOut*/);
3364 vrc = mRecording.mAudioRec->InitializeConfig(&DrvCfgVideoRec);
3365 AssertRCStmt(vrc, throw ConfigError(__FUNCTION__, vrc, "Recording.mAudioRec->InitializeConfig failed"));
3366 }
3367 idxAudioLun++;
3368#endif
3369
3370 if (fDebugEnabled)
3371 {
3372#ifdef VBOX_WITH_AUDIO_DEBUG
3373# ifdef VBOX_WITH_AUDIO_VALIDATIONKIT
3374 /*
3375 * When both, ValidationKit and Debug mode (for audio) are enabled,
3376 * skip configuring the Debug audio driver, as both modes can
3377 * mess with the audio data and would lead to side effects.
3378 *
3379 * The ValidationKit audio driver has precedence over the Debug audio driver.
3380 *
3381 * This also can (and will) be used in VBox release builds.
3382 */
3383 if (fValKitEnabled)
3384 {
3385 LogRel(("Audio: Warning: ValidationKit running and Debug mode enabled -- disabling Debug driver\n"));
3386 }
3387 else /* Debug mode active -- run both (nice for catching errors / doing development). */
3388 {
3389 /*
3390 * The ValidationKit backend.
3391 */
3392 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", idxAudioLun);
3393 i_configAudioDriver(virtualBox, pMachine, pLunL0, "ValidationKitAudio",
3394 !!fAudioEnabledIn, !!fAudioEnabledOut);
3395 idxAudioLun++;
3396# endif /* VBOX_WITH_AUDIO_VALIDATIONKIT */
3397 /*
3398 * The Debug audio backend.
3399 */
3400 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", idxAudioLun);
3401 i_configAudioDriver(virtualBox, pMachine, pLunL0, "DebugAudio",
3402 !!fAudioEnabledIn, !!fAudioEnabledOut);
3403 idxAudioLun++;
3404# ifdef VBOX_WITH_AUDIO_VALIDATIONKIT
3405 }
3406# endif /* VBOX_WITH_AUDIO_VALIDATIONKIT */
3407#endif /* VBOX_WITH_AUDIO_DEBUG */
3408
3409 /*
3410 * Tweak the logging groups.
3411 */
3412 Utf8Str strGroups("drv_audio.e.l.l2.l3.f"
3413 " audio_mixer.e.l.l2.l3.f"
3414 " dev_hda_codec.e.l.l2.l3.f"
3415 " dev_hda.e.l.l2.l3.f"
3416 " dev_ac97.e.l.l2.l3.f"
3417 " dev_sb16.e.l.l2.l3.f");
3418
3419 LogRel(("Audio: Debug level set to %RU32\n", uDebugLevel));
3420
3421 switch (uDebugLevel)
3422 {
3423 case 0:
3424 strGroups += " drv_host_audio.e.l.l2.l3.f";
3425 break;
3426 case 1:
3427 RT_FALL_THROUGH();
3428 case 2:
3429 RT_FALL_THROUGH();
3430 case 3:
3431 strGroups += " drv_host_audio.e.l.l2.l3.f+audio_test.e.l.l2.l3.f";
3432 break;
3433 case 4:
3434 RT_FALL_THROUGH();
3435 default:
3436 strGroups += " drv_host_audio.e.l.l2.l3.l4.f+audio_test.e.l.l2.l3.l4.f";
3437 break;
3438 }
3439
3440 vrc = RTLogGroupSettings(RTLogRelGetDefaultInstance(), strGroups.c_str());
3441 if (RT_FAILURE(vrc))
3442 LogRel(("Audio: Setting debug logging failed, vrc=%Rrc\n", vrc));
3443 }
3444 }
3445
3446#ifdef VBOX_WITH_SHARED_CLIPBOARD
3447 /*
3448 * Shared Clipboard.
3449 */
3450 {
3451 ClipboardMode_T enmClipboardMode = ClipboardMode_Disabled;
3452 hrc = pMachine->COMGETTER(ClipboardMode)(&enmClipboardMode); H();
3453# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
3454 BOOL fFileTransfersEnabled;
3455 hrc = pMachine->COMGETTER(ClipboardFileTransfersEnabled)(&fFileTransfersEnabled); H();
3456#endif
3457
3458 /* Load the service */
3459 vrc = pVMMDev->hgcmLoadService("VBoxSharedClipboard", "VBoxSharedClipboard");
3460 if (RT_SUCCESS(vrc))
3461 {
3462 LogRel(("Shared Clipboard: Service loaded\n"));
3463
3464 /* Set initial clipboard mode. */
3465 vrc = i_changeClipboardMode(enmClipboardMode);
3466 AssertLogRelMsg(RT_SUCCESS(vrc), ("Shared Clipboard: Failed to set initial clipboard mode (%d): vrc=%Rrc\n",
3467 enmClipboardMode, vrc));
3468
3469 /* Setup the service. */
3470 VBOXHGCMSVCPARM parm;
3471 HGCMSvcSetU32(&parm, !i_useHostClipboard());
3472 vrc = pVMMDev->hgcmHostCall("VBoxSharedClipboard", VBOX_SHCL_HOST_FN_SET_HEADLESS, 1, &parm);
3473 AssertLogRelMsg(RT_SUCCESS(vrc), ("Shared Clipboard: Failed to set initial headless mode (%RTbool): vrc=%Rrc\n",
3474 !i_useHostClipboard(), vrc));
3475
3476# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
3477 vrc = i_changeClipboardFileTransferMode(RT_BOOL(fFileTransfersEnabled));
3478 AssertLogRelMsg(RT_SUCCESS(vrc), ("Shared Clipboard: Failed to set initial file transfers mode (%u): vrc=%Rrc\n",
3479 fFileTransfersEnabled, vrc));
3480
3481 /** @todo Register area callbacks? (See also deregistration todo in Console::i_powerDown.) */
3482# endif
3483 }
3484 else
3485 LogRel(("Shared Clipboard: Not available, vrc=%Rrc\n", vrc));
3486 vrc = VINF_SUCCESS; /* None of the potential failures above are fatal. */
3487 }
3488#endif /* VBOX_WITH_SHARED_CLIPBOARD */
3489
3490 /*
3491 * HGCM HostChannel.
3492 */
3493 {
3494 Bstr value;
3495 hrc = pMachine->GetExtraData(Bstr("HGCM/HostChannel").raw(),
3496 value.asOutParam());
3497
3498 if ( hrc == S_OK
3499 && value == "1")
3500 {
3501 vrc = pVMMDev->hgcmLoadService("VBoxHostChannel", "VBoxHostChannel");
3502 if (RT_FAILURE(vrc))
3503 {
3504 LogRel(("VBoxHostChannel is not available, vrc=%Rrc\n", vrc));
3505 /* That is not a fatal failure. */
3506 vrc = VINF_SUCCESS;
3507 }
3508 }
3509 }
3510
3511#ifdef VBOX_WITH_DRAG_AND_DROP
3512 /*
3513 * Drag and Drop.
3514 */
3515 {
3516 DnDMode_T enmMode = DnDMode_Disabled;
3517 hrc = pMachine->COMGETTER(DnDMode)(&enmMode); H();
3518
3519 /* Load the service */
3520 vrc = pVMMDev->hgcmLoadService("VBoxDragAndDropSvc", "VBoxDragAndDropSvc");
3521 if (RT_FAILURE(vrc))
3522 {
3523 LogRel(("Drag and drop service is not available, vrc=%Rrc\n", vrc));
3524 /* That is not a fatal failure. */
3525 vrc = VINF_SUCCESS;
3526 }
3527 else
3528 {
3529 vrc = HGCMHostRegisterServiceExtension(&m_hHgcmSvcExtDragAndDrop, "VBoxDragAndDropSvc",
3530 &GuestDnD::notifyDnDDispatcher,
3531 GuestDnDInst());
3532 if (RT_FAILURE(vrc))
3533 Log(("Cannot register VBoxDragAndDropSvc extension, vrc=%Rrc\n", vrc));
3534 else
3535 {
3536 LogRel(("Drag and drop service loaded\n"));
3537 vrc = i_changeDnDMode(enmMode);
3538 }
3539 }
3540 }
3541#endif /* VBOX_WITH_DRAG_AND_DROP */
3542
3543#if defined(VBOX_WITH_TPM)
3544 /*
3545 * Configure the Trusted Platform Module.
3546 */
3547 ComObjPtr<ITrustedPlatformModule> ptrTpm;
3548 TpmType_T enmTpmType = TpmType_None;
3549
3550 hrc = pMachine->COMGETTER(TrustedPlatformModule)(ptrTpm.asOutParam()); H();
3551 hrc = ptrTpm->COMGETTER(Type)(&enmTpmType); H();
3552 if (enmTpmType != TpmType_None)
3553 {
3554 InsertConfigNode(pDevices, "tpm", &pDev);
3555 InsertConfigNode(pDev, "0", &pInst);
3556 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3557 InsertConfigNode(pInst, "Config", &pCfg);
3558 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3559
3560 switch (enmTpmType)
3561 {
3562 case TpmType_v1_2:
3563 case TpmType_v2_0:
3564 InsertConfigString(pLunL0, "Driver", "TpmEmuTpms");
3565 InsertConfigNode(pLunL0, "Config", &pCfg);
3566 InsertConfigInteger(pCfg, "TpmVersion", enmTpmType == TpmType_v1_2 ? 1 : 2);
3567 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
3568 InsertConfigString(pLunL1, "Driver", "NvramStore");
3569 break;
3570 case TpmType_Host:
3571#if defined(RT_OS_LINUX) || defined(RT_OS_WINDOWS)
3572 InsertConfigString(pLunL0, "Driver", "TpmHost");
3573 InsertConfigNode(pLunL0, "Config", &pCfg);
3574#endif
3575 break;
3576 case TpmType_Swtpm:
3577 hrc = ptrTpm->COMGETTER(Location)(bstr.asOutParam()); H();
3578 InsertConfigString(pLunL0, "Driver", "TpmEmu");
3579 InsertConfigNode(pLunL0, "Config", &pCfg);
3580 InsertConfigString(pCfg, "Location", bstr);
3581 break;
3582 default:
3583 AssertFailedBreak();
3584 }
3585 }
3586#endif
3587
3588 /*
3589 * ACPI
3590 */
3591 BOOL fACPI;
3592 hrc = biosSettings->COMGETTER(ACPIEnabled)(&fACPI); H();
3593 if (fACPI)
3594 {
3595 /* Always show the CPU leafs when we have multiple VCPUs or when the IO-APIC is enabled.
3596 * The Windows SMP kernel needs a CPU leaf or else its idle loop will burn cpu cycles; the
3597 * intelppm driver refuses to register an idle state handler.
3598 * Always show CPU leafs for OS X guests. */
3599 BOOL fShowCpu = fOsXGuest;
3600 if (cCpus > 1 || fIOAPIC)
3601 fShowCpu = true;
3602
3603 BOOL fCpuHotPlug;
3604 hrc = pMachine->COMGETTER(CPUHotPlugEnabled)(&fCpuHotPlug); H();
3605
3606 InsertConfigNode(pDevices, "acpi", &pDev);
3607 InsertConfigNode(pDev, "0", &pInst);
3608 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3609 InsertConfigNode(pInst, "Config", &pCfg);
3610 hrc = pBusMgr->assignPCIDevice("acpi", pInst); H();
3611
3612 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
3613
3614 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
3615 InsertConfigInteger(pCfg, "FdcEnabled", fFdcEnabled);
3616 InsertConfigInteger(pCfg, "HpetEnabled", fHPETEnabled);
3617 InsertConfigInteger(pCfg, "SmcEnabled", fSmcEnabled);
3618 InsertConfigInteger(pCfg, "ShowRtc", fShowRtc);
3619 if (fOsXGuest && !llBootNics.empty())
3620 {
3621 BootNic aNic = llBootNics.front();
3622 uint32_t u32NicPCIAddr = (aNic.mPCIAddress.miDevice << 16) | aNic.mPCIAddress.miFn;
3623 InsertConfigInteger(pCfg, "NicPciAddress", u32NicPCIAddr);
3624 }
3625 if (fOsXGuest && fAudioEnabled)
3626 {
3627 PCIBusAddress Address;
3628 if (pBusMgr->findPCIAddress("hda", 0, Address))
3629 {
3630 uint32_t u32AudioPCIAddr = (Address.miDevice << 16) | Address.miFn;
3631 InsertConfigInteger(pCfg, "AudioPciAddress", u32AudioPCIAddr);
3632 }
3633 }
3634 if (fOsXGuest)
3635 {
3636 PCIBusAddress Address;
3637 if (pBusMgr->findPCIAddress("nvme", 0, Address))
3638 {
3639 uint32_t u32NvmePCIAddr = (Address.miDevice << 16) | Address.miFn;
3640 InsertConfigInteger(pCfg, "NvmePciAddress", u32NvmePCIAddr);
3641 }
3642 }
3643 if (enmIommuType == IommuType_AMD)
3644 {
3645 PCIBusAddress Address;
3646 if (pBusMgr->findPCIAddress("iommu-amd", 0, Address))
3647 {
3648 uint32_t u32IommuAddress = (Address.miDevice << 16) | Address.miFn;
3649 InsertConfigInteger(pCfg, "IommuAmdEnabled", true);
3650 InsertConfigInteger(pCfg, "IommuPciAddress", u32IommuAddress);
3651 if (pBusMgr->findPCIAddress("sb-ioapic", 0, Address))
3652 {
3653 uint32_t const u32SbIoapicAddress = (Address.miDevice << 16) | Address.miFn;
3654 InsertConfigInteger(pCfg, "SbIoApicPciAddress", u32SbIoapicAddress);
3655 }
3656 else
3657 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
3658 N_("AMD IOMMU is enabled, but the I/O APIC is not assigned a PCI address!"));
3659 }
3660 }
3661 else if (enmIommuType == IommuType_Intel)
3662 {
3663 PCIBusAddress Address;
3664 if (pBusMgr->findPCIAddress("iommu-intel", 0, Address))
3665 {
3666 uint32_t u32IommuAddress = (Address.miDevice << 16) | Address.miFn;
3667 InsertConfigInteger(pCfg, "IommuIntelEnabled", true);
3668 InsertConfigInteger(pCfg, "IommuPciAddress", u32IommuAddress);
3669 if (pBusMgr->findPCIAddress("sb-ioapic", 0, Address))
3670 {
3671 uint32_t const u32SbIoapicAddress = (Address.miDevice << 16) | Address.miFn;
3672 InsertConfigInteger(pCfg, "SbIoApicPciAddress", u32SbIoapicAddress);
3673 }
3674 else
3675 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
3676 N_("Intel IOMMU is enabled, but the I/O APIC is not assigned a PCI address!"));
3677 }
3678 }
3679
3680 InsertConfigInteger(pCfg, "IocPciAddress", uIocPCIAddress);
3681 if (chipsetType == ChipsetType_ICH9)
3682 {
3683 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
3684 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
3685 /* 64-bit prefetch window root resource: Only for ICH9 and if PAE or Long Mode is enabled (@bugref{5454}). */
3686 if (fIsGuest64Bit || fEnablePAE)
3687 InsertConfigInteger(pCfg, "PciPref64Enabled", 1);
3688 }
3689 InsertConfigInteger(pCfg, "HostBusPciAddress", uHbcPCIAddress);
3690 InsertConfigInteger(pCfg, "ShowCpu", fShowCpu);
3691 InsertConfigInteger(pCfg, "CpuHotPlug", fCpuHotPlug);
3692
3693 InsertConfigInteger(pCfg, "Serial0IoPortBase", auSerialIoPortBase[0]);
3694 InsertConfigInteger(pCfg, "Serial0Irq", auSerialIrq[0]);
3695
3696 InsertConfigInteger(pCfg, "Serial1IoPortBase", auSerialIoPortBase[1]);
3697 InsertConfigInteger(pCfg, "Serial1Irq", auSerialIrq[1]);
3698
3699 if (auSerialIoPortBase[2])
3700 {
3701 InsertConfigInteger(pCfg, "Serial2IoPortBase", auSerialIoPortBase[2]);
3702 InsertConfigInteger(pCfg, "Serial2Irq", auSerialIrq[2]);
3703 }
3704
3705 if (auSerialIoPortBase[3])
3706 {
3707 InsertConfigInteger(pCfg, "Serial3IoPortBase", auSerialIoPortBase[3]);
3708 InsertConfigInteger(pCfg, "Serial3Irq", auSerialIrq[3]);
3709 }
3710
3711 InsertConfigInteger(pCfg, "Parallel0IoPortBase", auParallelIoPortBase[0]);
3712 InsertConfigInteger(pCfg, "Parallel0Irq", auParallelIrq[0]);
3713
3714 InsertConfigInteger(pCfg, "Parallel1IoPortBase", auParallelIoPortBase[1]);
3715 InsertConfigInteger(pCfg, "Parallel1Irq", auParallelIrq[1]);
3716
3717#if defined(VBOX_WITH_TPM)
3718 switch (enmTpmType)
3719 {
3720 case TpmType_v1_2:
3721 InsertConfigString(pCfg, "TpmMode", "tis1.2");
3722 break;
3723 case TpmType_v2_0:
3724 InsertConfigString(pCfg, "TpmMode", "fifo2.0");
3725 break;
3726 /** @todo Host and swtpm. */
3727 default:
3728 break;
3729 }
3730#endif
3731
3732 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3733 InsertConfigString(pLunL0, "Driver", "ACPIHost");
3734 InsertConfigNode(pLunL0, "Config", &pCfg);
3735
3736 /* Attach the dummy CPU drivers */
3737 for (ULONG iCpuCurr = 1; iCpuCurr < cCpus; iCpuCurr++)
3738 {
3739 BOOL fCpuAttached = true;
3740
3741 if (fCpuHotPlug)
3742 {
3743 hrc = pMachine->GetCPUStatus(iCpuCurr, &fCpuAttached); H();
3744 }
3745
3746 if (fCpuAttached)
3747 {
3748 InsertConfigNode(pInst, Utf8StrFmt("LUN#%u", iCpuCurr).c_str(), &pLunL0);
3749 InsertConfigString(pLunL0, "Driver", "ACPICpu");
3750 InsertConfigNode(pLunL0, "Config", &pCfg);
3751 }
3752 }
3753 }
3754
3755 /*
3756 * Configure DBGF (Debug(ger) Facility) and DBGC (Debugger Console).
3757 */
3758 {
3759 PCFGMNODE pDbgf;
3760 InsertConfigNode(pRoot, "DBGF", &pDbgf);
3761
3762 /* Paths to search for debug info and such things. */
3763 hrc = pMachine->COMGETTER(SettingsFilePath)(bstr.asOutParam()); H();
3764 Utf8Str strSettingsPath(bstr);
3765 bstr.setNull();
3766 strSettingsPath.stripFilename();
3767 strSettingsPath.append("/");
3768
3769 char szHomeDir[RTPATH_MAX + 1];
3770 int vrc2 = RTPathUserHome(szHomeDir, sizeof(szHomeDir) - 1);
3771 if (RT_FAILURE(vrc2))
3772 szHomeDir[0] = '\0';
3773 RTPathEnsureTrailingSeparator(szHomeDir, sizeof(szHomeDir));
3774
3775
3776 Utf8Str strPath;
3777 strPath.append(strSettingsPath).append("debug/;");
3778 strPath.append(strSettingsPath).append(";");
3779 strPath.append("cache*").append(strSettingsPath).append("dbgcache/;"); /* handy for symlinking to actual cache */
3780 strPath.append(szHomeDir);
3781
3782 InsertConfigString(pDbgf, "Path", strPath.c_str());
3783
3784 /* Tracing configuration. */
3785 BOOL fTracingEnabled;
3786 hrc = pMachine->COMGETTER(TracingEnabled)(&fTracingEnabled); H();
3787 if (fTracingEnabled)
3788 InsertConfigInteger(pDbgf, "TracingEnabled", 1);
3789
3790 hrc = pMachine->COMGETTER(TracingConfig)(bstr.asOutParam()); H();
3791 if (fTracingEnabled)
3792 InsertConfigString(pDbgf, "TracingConfig", bstr);
3793
3794 BOOL fAllowTracingToAccessVM;
3795 hrc = pMachine->COMGETTER(AllowTracingToAccessVM)(&fAllowTracingToAccessVM); H();
3796 if (fAllowTracingToAccessVM)
3797 InsertConfigInteger(pPDM, "AllowTracingToAccessVM", 1);
3798
3799 /* Debugger console config. */
3800 PCFGMNODE pDbgc;
3801 InsertConfigNode(pRoot, "DBGC", &pDbgc);
3802
3803 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
3804 Utf8Str strVBoxHome = bstr;
3805 bstr.setNull();
3806 if (strVBoxHome.isNotEmpty())
3807 strVBoxHome.append("/");
3808 else
3809 {
3810 strVBoxHome = szHomeDir;
3811 strVBoxHome.append("/.vbox");
3812 }
3813
3814 Utf8Str strFile(strVBoxHome);
3815 strFile.append("dbgc-history");
3816 InsertConfigString(pDbgc, "HistoryFile", strFile);
3817
3818 strFile = strSettingsPath;
3819 strFile.append("dbgc-init");
3820 InsertConfigString(pDbgc, "LocalInitScript", strFile);
3821
3822 strFile = strVBoxHome;
3823 strFile.append("dbgc-init");
3824 InsertConfigString(pDbgc, "GlobalInitScript", strFile);
3825
3826 /*
3827 * Configure guest debug settings.
3828 */
3829 ComObjPtr<IGuestDebugControl> ptrGstDbgCtrl;
3830 GuestDebugProvider_T enmGstDbgProvider = GuestDebugProvider_None;
3831
3832 hrc = pMachine->COMGETTER(GuestDebugControl)(ptrGstDbgCtrl.asOutParam()); H();
3833 hrc = ptrGstDbgCtrl->COMGETTER(DebugProvider)(&enmGstDbgProvider); H();
3834 if (enmGstDbgProvider != GuestDebugProvider_None)
3835 {
3836 GuestDebugIoProvider_T enmGstDbgIoProvider = GuestDebugIoProvider_None;
3837 hrc = ptrGstDbgCtrl->COMGETTER(DebugIoProvider)(&enmGstDbgIoProvider); H();
3838 hrc = ptrGstDbgCtrl->COMGETTER(DebugAddress)(bstr.asOutParam()); H();
3839 Utf8Str strAddress = bstr;
3840 bstr.setNull();
3841
3842 ULONG ulPort = 0;
3843 hrc = ptrGstDbgCtrl->COMGETTER(DebugPort)(&ulPort); H();
3844
3845 PCFGMNODE pDbgSettings;
3846 InsertConfigNode(pDbgc, "Dbg", &pDbgSettings);
3847 InsertConfigString(pDbgSettings, "Address", strAddress);
3848 InsertConfigInteger(pDbgSettings, "Port", ulPort);
3849
3850 switch (enmGstDbgProvider)
3851 {
3852 case GuestDebugProvider_Native:
3853 InsertConfigString(pDbgSettings, "StubType", "Native");
3854 break;
3855 case GuestDebugProvider_GDB:
3856 InsertConfigString(pDbgSettings, "StubType", "Gdb");
3857 break;
3858 case GuestDebugProvider_KD:
3859 InsertConfigString(pDbgSettings, "StubType", "Kd");
3860 break;
3861 default:
3862 AssertFailed();
3863 break;
3864 }
3865
3866 switch (enmGstDbgIoProvider)
3867 {
3868 case GuestDebugIoProvider_TCP:
3869 InsertConfigString(pDbgSettings, "Provider", "tcp");
3870 break;
3871 case GuestDebugIoProvider_UDP:
3872 InsertConfigString(pDbgSettings, "Provider", "udp");
3873 break;
3874 case GuestDebugIoProvider_IPC:
3875 InsertConfigString(pDbgSettings, "Provider", "ipc");
3876 break;
3877 default:
3878 AssertFailed();
3879 break;
3880 }
3881 }
3882 }
3883 }
3884 catch (ConfigError &x)
3885 {
3886 // InsertConfig threw something:
3887 pVMM->pfnVMR3SetError(pUVM, x.m_vrc, RT_SRC_POS, "Caught ConfigError: %Rrc - %s", x.m_vrc, x.what());
3888 return x.m_vrc;
3889 }
3890 catch (HRESULT hrcXcpt)
3891 {
3892 AssertLogRelMsgFailedReturn(("hrc=%Rhrc\n", hrcXcpt), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
3893 }
3894
3895#ifdef VBOX_WITH_EXTPACK
3896 /*
3897 * Call the extension pack hooks if everything went well thus far.
3898 */
3899 if (RT_SUCCESS(vrc))
3900 {
3901 pAlock->release();
3902 vrc = mptrExtPackManager->i_callAllVmConfigureVmmHooks(this, pVM, pVMM);
3903 pAlock->acquire();
3904 }
3905#endif
3906
3907 /*
3908 * Apply the CFGM overlay.
3909 */
3910 if (RT_SUCCESS(vrc))
3911 vrc = i_configCfgmOverlay(pRoot, virtualBox, pMachine);
3912
3913 /*
3914 * Dump all extradata API settings tweaks, both global and per VM.
3915 */
3916 if (RT_SUCCESS(vrc))
3917 vrc = i_configDumpAPISettingsTweaks(virtualBox, pMachine);
3918
3919#undef H
3920
3921 pAlock->release(); /* Avoid triggering the lock order inversion check. */
3922
3923 /*
3924 * Register VM state change handler.
3925 */
3926 int vrc2 = pVMM->pfnVMR3AtStateRegister(pUVM, Console::i_vmstateChangeCallback, this);
3927 AssertRC(vrc2);
3928 if (RT_SUCCESS(vrc))
3929 vrc = vrc2;
3930
3931 /*
3932 * Register VM runtime error handler.
3933 */
3934 vrc2 = pVMM->pfnVMR3AtRuntimeErrorRegister(pUVM, Console::i_atVMRuntimeErrorCallback, this);
3935 AssertRC(vrc2);
3936 if (RT_SUCCESS(vrc))
3937 vrc = vrc2;
3938
3939 pAlock->acquire();
3940
3941 LogFlowFunc(("vrc = %Rrc\n", vrc));
3942 LogFlowFuncLeave();
3943
3944 return vrc;
3945}
3946
3947/**
3948 * Configures an audio driver via CFGM by getting (optional) values from extra data.
3949 *
3950 * @param pVirtualBox Pointer to IVirtualBox instance.
3951 * @param pMachine Pointer to IMachine instance.
3952 * @param pLUN Pointer to CFGM node of LUN (the driver) to configure.
3953 * @param pszDrvName Name of the driver to configure.
3954 * @param fAudioEnabledIn IAudioAdapter::enabledIn value.
3955 * @param fAudioEnabledOut IAudioAdapter::enabledOut value.
3956 *
3957 * @throws ConfigError or HRESULT on if there is trouble.
3958 */
3959void Console::i_configAudioDriver(IVirtualBox *pVirtualBox, IMachine *pMachine, PCFGMNODE pLUN, const char *pszDrvName,
3960 bool fAudioEnabledIn, bool fAudioEnabledOut)
3961{
3962#define H() AssertLogRelMsgStmt(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), \
3963 throw ConfigError(__FUNCTION__, VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR, "line: " RT_XSTR(__LINE__)))
3964
3965 InsertConfigString(pLUN, "Driver", "AUDIO");
3966
3967 PCFGMNODE pCfg;
3968 InsertConfigNode(pLUN, "Config", &pCfg);
3969 InsertConfigString(pCfg, "DriverName", pszDrvName);
3970 InsertConfigInteger(pCfg, "InputEnabled", fAudioEnabledIn);
3971 InsertConfigInteger(pCfg, "OutputEnabled", fAudioEnabledOut);
3972
3973 Utf8Str strTmp;
3974 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/Audio/Debug/Enabled", &strTmp);
3975 const uint64_t fDebugEnabled = strTmp.equalsIgnoreCase("true") || strTmp.equalsIgnoreCase("1");
3976 if (fDebugEnabled)
3977 {
3978 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
3979
3980 Utf8Str strDebugPathOut;
3981 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/Audio/Debug/PathOut", &strDebugPathOut);
3982 InsertConfigString(pCfg, "DebugPathOut", strDebugPathOut.c_str());
3983 }
3984
3985 /*
3986 * PCM input parameters (playback + recording).
3987 * We have host driver specific ones as: VBoxInternal2/Audio/<DrvName>/<Value>
3988 * And global ones for all host drivers: VBoxInternal2/Audio/<Value>
3989 */
3990 for (unsigned iDir = 0; iDir < 2; iDir++)
3991 {
3992 static const struct
3993 {
3994 const char *pszExtraName;
3995 const char *pszCfgmName;
3996 } s_aToCopy[] =
3997 { /* PCM parameters: */
3998 { "PCMSampleBit", "PCMSampleBit" },
3999 { "PCMSampleHz", "PCMSampleHz" },
4000 { "PCMSampleSigned", "PCMSampleSigned" },
4001 { "PCMSampleSwapEndian", "PCMSampleSwapEndian" },
4002 { "PCMSampleChannels", "PCMSampleChannels" },
4003 /* Buffering stuff: */
4004 { "PeriodSizeMs", "PeriodSizeMs" },
4005 { "BufferSizeMs", "BufferSizeMs" },
4006 { "PreBufferSizeMs", "PreBufferSizeMs" },
4007 };
4008
4009 PCFGMNODE pDirNode = NULL;
4010 const char *pszDir = iDir == 0 ? "In" : "Out";
4011 for (size_t i = 0; i < RT_ELEMENTS(s_aToCopy); i++)
4012 {
4013 char szExtra[128];
4014 RTStrPrintf(szExtra, sizeof(szExtra), "VBoxInternal2/Audio/%s/%s%s", pszDrvName, s_aToCopy[i].pszExtraName, pszDir);
4015 GetExtraDataBoth(pVirtualBox, pMachine, szExtra, &strTmp); /* throws hrc */
4016 if (strTmp.isEmpty())
4017 {
4018 RTStrPrintf(szExtra, sizeof(szExtra), "VBoxInternal2/Audio/%s%s", s_aToCopy[i].pszExtraName, pszDir);
4019 GetExtraDataBoth(pVirtualBox, pMachine, szExtra, &strTmp);
4020 if (strTmp.isEmpty())
4021 continue;
4022 }
4023
4024 uint32_t uValue;
4025 int vrc = RTStrToUInt32Full(strTmp.c_str(), 0, &uValue);
4026 if (RT_SUCCESS(vrc))
4027 {
4028 if (!pDirNode)
4029 InsertConfigNode(pCfg, pszDir, &pDirNode);
4030 InsertConfigInteger(pDirNode, s_aToCopy[i].pszCfgmName, uValue);
4031 }
4032 else
4033 LogRel(("Ignoring malformed 32-bit unsigned integer config value '%s' = '%s': %Rrc\n", szExtra, strTmp.c_str(), vrc));
4034 }
4035 }
4036
4037 PCFGMNODE pLunL1;
4038 InsertConfigNode(pLUN, "AttachedDriver", &pLunL1);
4039 InsertConfigString(pLunL1, "Driver", pszDrvName);
4040 InsertConfigNode(pLunL1, "Config", &pCfg);
4041
4042#ifdef RT_OS_WINDOWS
4043 if (strcmp(pszDrvName, "HostAudioWas") == 0)
4044 {
4045 Bstr bstrTmp;
4046 HRESULT hrc = pMachine->COMGETTER(Id)(bstrTmp.asOutParam()); H();
4047 InsertConfigString(pCfg, "VmUuid", bstrTmp);
4048 }
4049#endif
4050
4051#if defined(RT_OS_WINDOWS) || defined(RT_OS_LINUX)
4052 if ( strcmp(pszDrvName, "HostAudioWas") == 0
4053 || strcmp(pszDrvName, "PulseAudio") == 0)
4054 {
4055 Bstr bstrTmp;
4056 HRESULT hrc = pMachine->COMGETTER(Name)(bstrTmp.asOutParam()); H();
4057 InsertConfigString(pCfg, "VmName", bstrTmp);
4058 }
4059#endif
4060
4061 LogFlowFunc(("szDrivName=%s\n", pszDrvName));
4062
4063#undef H
4064}
4065
4066/**
4067 * Applies the CFGM overlay as specified by VBoxInternal/XXX extra data
4068 * values.
4069 *
4070 * @returns VBox status code.
4071 * @param pRoot The root of the configuration tree.
4072 * @param pVirtualBox Pointer to the IVirtualBox interface.
4073 * @param pMachine Pointer to the IMachine interface.
4074 */
4075/* static */
4076int Console::i_configCfgmOverlay(PCFGMNODE pRoot, IVirtualBox *pVirtualBox, IMachine *pMachine)
4077{
4078 /*
4079 * CFGM overlay handling.
4080 *
4081 * Here we check the extra data entries for CFGM values
4082 * and create the nodes and insert the values on the fly. Existing
4083 * values will be removed and reinserted. CFGM is typed, so by default
4084 * we will guess whether it's a string or an integer (byte arrays are
4085 * not currently supported). It's possible to override this autodetection
4086 * by adding "string:", "integer:" or "bytes:" (future).
4087 *
4088 * We first perform a run on global extra data, then on the machine
4089 * extra data to support global settings with local overrides.
4090 */
4091 int vrc = VINF_SUCCESS;
4092 bool fFirst = true;
4093 try
4094 {
4095 /** @todo add support for removing nodes and byte blobs. */
4096 /*
4097 * Get the next key
4098 */
4099 SafeArray<BSTR> aGlobalExtraDataKeys;
4100 SafeArray<BSTR> aMachineExtraDataKeys;
4101 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
4102 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
4103
4104 // remember the no. of global values so we can call the correct method below
4105 size_t cGlobalValues = aGlobalExtraDataKeys.size();
4106
4107 hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
4108 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
4109
4110 // build a combined list from global keys...
4111 std::list<Utf8Str> llExtraDataKeys;
4112
4113 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); ++i)
4114 llExtraDataKeys.push_back(Utf8Str(aGlobalExtraDataKeys[i]));
4115 // ... and machine keys
4116 for (size_t i = 0; i < aMachineExtraDataKeys.size(); ++i)
4117 llExtraDataKeys.push_back(Utf8Str(aMachineExtraDataKeys[i]));
4118
4119 size_t i2 = 0;
4120 for (std::list<Utf8Str>::const_iterator it = llExtraDataKeys.begin();
4121 it != llExtraDataKeys.end();
4122 ++it, ++i2)
4123 {
4124 const Utf8Str &strKey = *it;
4125
4126 /*
4127 * We only care about keys starting with "VBoxInternal/" (skip "G:" or "M:")
4128 */
4129 if (!strKey.startsWith("VBoxInternal/"))
4130 continue;
4131
4132 const char *pszExtraDataKey = strKey.c_str() + sizeof("VBoxInternal/") - 1;
4133
4134 // get the value
4135 Bstr bstrExtraDataValue;
4136 if (i2 < cGlobalValues)
4137 // this is still one of the global values:
4138 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(), bstrExtraDataValue.asOutParam());
4139 else
4140 hrc = pMachine->GetExtraData(Bstr(strKey).raw(), bstrExtraDataValue.asOutParam());
4141 if (FAILED(hrc))
4142 LogRel(("Warning: Cannot get extra data key %s, hrc = %Rhrc\n", strKey.c_str(), hrc));
4143
4144 if (fFirst)
4145 {
4146 fFirst = false;
4147 LogRel(("Extradata overrides:\n"));
4148 }
4149 LogRel((" %s=\"%ls\"%s\n", strKey.c_str(), bstrExtraDataValue.raw(), i2 < cGlobalValues ? " (global)" : ""));
4150
4151 /*
4152 * The key will be in the format "Node1/Node2/Value" or simply "Value".
4153 * Split the two and get the node, delete the value and create the node
4154 * if necessary.
4155 */
4156 PCFGMNODE pNode;
4157 const char *pszCFGMValueName = strrchr(pszExtraDataKey, '/');
4158 if (pszCFGMValueName)
4159 {
4160 /* terminate the node and advance to the value (Utf8Str might not
4161 offically like this but wtf) */
4162 *(char *)pszCFGMValueName = '\0';
4163 ++pszCFGMValueName;
4164
4165 /* does the node already exist? */
4166 pNode = mpVMM->pfnCFGMR3GetChild(pRoot, pszExtraDataKey);
4167 if (pNode)
4168 mpVMM->pfnCFGMR3RemoveValue(pNode, pszCFGMValueName);
4169 else
4170 {
4171 /* create the node */
4172 vrc = mpVMM->pfnCFGMR3InsertNode(pRoot, pszExtraDataKey, &pNode);
4173 if (RT_FAILURE(vrc))
4174 {
4175 AssertLogRelMsgRC(vrc, ("failed to insert node '%s'\n", pszExtraDataKey));
4176 continue;
4177 }
4178 Assert(pNode);
4179 }
4180 }
4181 else
4182 {
4183 /* root value (no node path). */
4184 pNode = pRoot;
4185 pszCFGMValueName = pszExtraDataKey;
4186 pszExtraDataKey--;
4187 mpVMM->pfnCFGMR3RemoveValue(pNode, pszCFGMValueName);
4188 }
4189
4190 /*
4191 * Now let's have a look at the value.
4192 * Empty strings means that we should remove the value, which we've
4193 * already done above.
4194 */
4195 Utf8Str strCFGMValueUtf8(bstrExtraDataValue);
4196 if (strCFGMValueUtf8.isNotEmpty())
4197 {
4198 uint64_t u64Value;
4199
4200 /* check for type prefix first. */
4201 if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("string:")))
4202 vrc = mpVMM->pfnCFGMR3InsertString(pNode, pszCFGMValueName, strCFGMValueUtf8.c_str() + sizeof("string:") - 1);
4203 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("integer:")))
4204 {
4205 vrc = RTStrToUInt64Full(strCFGMValueUtf8.c_str() + sizeof("integer:") - 1, 0, &u64Value);
4206 if (RT_SUCCESS(vrc))
4207 vrc = mpVMM->pfnCFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
4208 }
4209 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("bytes:")))
4210 {
4211 char const *pszBase64 = strCFGMValueUtf8.c_str() + sizeof("bytes:") - 1;
4212 ssize_t cbValue = RTBase64DecodedSize(pszBase64, NULL);
4213 if (cbValue > 0)
4214 {
4215 void *pvBytes = RTMemTmpAlloc(cbValue);
4216 if (pvBytes)
4217 {
4218 vrc = RTBase64Decode(pszBase64, pvBytes, cbValue, NULL, NULL);
4219 if (RT_SUCCESS(vrc))
4220 vrc = mpVMM->pfnCFGMR3InsertBytes(pNode, pszCFGMValueName, pvBytes, cbValue);
4221 RTMemTmpFree(pvBytes);
4222 }
4223 else
4224 vrc = VERR_NO_TMP_MEMORY;
4225 }
4226 else if (cbValue == 0)
4227 vrc = mpVMM->pfnCFGMR3InsertBytes(pNode, pszCFGMValueName, NULL, 0);
4228 else
4229 vrc = VERR_INVALID_BASE64_ENCODING;
4230 }
4231 /* auto detect type. */
4232 else if (RT_SUCCESS(RTStrToUInt64Full(strCFGMValueUtf8.c_str(), 0, &u64Value)))
4233 vrc = mpVMM->pfnCFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
4234 else
4235 vrc = mpVMM->pfnCFGMR3InsertString(pNode, pszCFGMValueName, strCFGMValueUtf8.c_str());
4236 AssertLogRelMsgRCBreak(vrc, ("failed to insert CFGM value '%s' to key '%s'\n",
4237 strCFGMValueUtf8.c_str(), pszExtraDataKey));
4238 }
4239 }
4240 }
4241 catch (ConfigError &x)
4242 {
4243 // InsertConfig threw something:
4244 return x.m_vrc;
4245 }
4246 return vrc;
4247}
4248
4249/**
4250 * Dumps the API settings tweaks as specified by VBoxInternal2/XXX extra data
4251 * values.
4252 *
4253 * @returns VBox status code.
4254 * @param pVirtualBox Pointer to the IVirtualBox interface.
4255 * @param pMachine Pointer to the IMachine interface.
4256 */
4257/* static */
4258int Console::i_configDumpAPISettingsTweaks(IVirtualBox *pVirtualBox, IMachine *pMachine)
4259{
4260 {
4261 SafeArray<BSTR> aGlobalExtraDataKeys;
4262 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
4263 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
4264 bool hasKey = false;
4265 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); i++)
4266 {
4267 Utf8Str strKey(aGlobalExtraDataKeys[i]);
4268 if (!strKey.startsWith("VBoxInternal2/"))
4269 continue;
4270
4271 Bstr bstrValue;
4272 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
4273 bstrValue.asOutParam());
4274 if (FAILED(hrc))
4275 continue;
4276 if (!hasKey)
4277 LogRel(("Global extradata API settings:\n"));
4278 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
4279 hasKey = true;
4280 }
4281 }
4282
4283 {
4284 SafeArray<BSTR> aMachineExtraDataKeys;
4285 HRESULT hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
4286 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
4287 bool hasKey = false;
4288 for (size_t i = 0; i < aMachineExtraDataKeys.size(); i++)
4289 {
4290 Utf8Str strKey(aMachineExtraDataKeys[i]);
4291 if (!strKey.startsWith("VBoxInternal2/"))
4292 continue;
4293
4294 Bstr bstrValue;
4295 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
4296 bstrValue.asOutParam());
4297 if (FAILED(hrc))
4298 continue;
4299 if (!hasKey)
4300 LogRel(("Per-VM extradata API settings:\n"));
4301 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
4302 hasKey = true;
4303 }
4304 }
4305
4306 return VINF_SUCCESS;
4307}
4308
4309int Console::i_configGraphicsController(PCFGMNODE pDevices,
4310 const GraphicsControllerType_T enmGraphicsController,
4311 BusAssignmentManager *pBusMgr,
4312 const ComPtr<IMachine> &ptrMachine,
4313 const ComPtr<IGraphicsAdapter> &ptrGraphicsAdapter,
4314 const ComPtr<IBIOSSettings> &ptrBiosSettings,
4315 bool fHMEnabled)
4316{
4317 // InsertConfig* throws
4318 try
4319 {
4320 PCFGMNODE pDev, pInst, pCfg, pLunL0;
4321 HRESULT hrc;
4322 Bstr bstr;
4323 const char *pcszDevice = "vga";
4324
4325#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4326 InsertConfigNode(pDevices, pcszDevice, &pDev);
4327 InsertConfigNode(pDev, "0", &pInst);
4328 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
4329
4330 hrc = pBusMgr->assignPCIDevice(pcszDevice, pInst); H();
4331 InsertConfigNode(pInst, "Config", &pCfg);
4332 ULONG cVRamMBs;
4333 hrc = ptrGraphicsAdapter->COMGETTER(VRAMSize)(&cVRamMBs); H();
4334 InsertConfigInteger(pCfg, "VRamSize", cVRamMBs * _1M);
4335 ULONG cMonitorCount;
4336 hrc = ptrGraphicsAdapter->COMGETTER(MonitorCount)(&cMonitorCount); H();
4337 InsertConfigInteger(pCfg, "MonitorCount", cMonitorCount);
4338#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
4339 InsertConfigInteger(pCfg, "R0Enabled", fHMEnabled);
4340#else
4341 NOREF(fHMEnabled);
4342#endif
4343 BOOL f3DEnabled;
4344 hrc = ptrGraphicsAdapter->COMGETTER(Accelerate3DEnabled)(&f3DEnabled); H();
4345 InsertConfigInteger(pCfg, "3DEnabled", f3DEnabled);
4346
4347 i_attachStatusDriver(pInst, DeviceType_Graphics3D);
4348
4349#ifdef VBOX_WITH_VMSVGA
4350 if ( enmGraphicsController == GraphicsControllerType_VMSVGA
4351 || enmGraphicsController == GraphicsControllerType_VBoxSVGA)
4352 {
4353 InsertConfigInteger(pCfg, "VMSVGAEnabled", true);
4354 if (enmGraphicsController == GraphicsControllerType_VMSVGA)
4355 {
4356 InsertConfigInteger(pCfg, "VMSVGAPciBarLayout", true);
4357 InsertConfigInteger(pCfg, "VMSVGAPciId", true);
4358 }
4359# ifdef VBOX_WITH_VMSVGA3D
4360 InsertConfigInteger(pCfg, "VMSVGA3dEnabled", f3DEnabled);
4361# else
4362 LogRel(("VMSVGA3d not available in this build!\n"));
4363# endif /* VBOX_WITH_VMSVGA3D */
4364 }
4365#else
4366 RT_NOREF(enmGraphicsController);
4367#endif /* VBOX_WITH_VMSVGA */
4368
4369 /* Custom VESA mode list */
4370 unsigned cModes = 0;
4371 for (unsigned iMode = 1; iMode <= 16; ++iMode)
4372 {
4373 char szExtraDataKey[sizeof("CustomVideoModeXX")];
4374 RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%u", iMode);
4375 hrc = ptrMachine->GetExtraData(Bstr(szExtraDataKey).raw(), bstr.asOutParam()); H();
4376 if (bstr.isEmpty())
4377 break;
4378 InsertConfigString(pCfg, szExtraDataKey, bstr);
4379 ++cModes;
4380 }
4381 InsertConfigInteger(pCfg, "CustomVideoModes", cModes);
4382
4383 /* VESA height reduction */
4384 ULONG ulHeightReduction;
4385 IFramebuffer *pFramebuffer = NULL;
4386 hrc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
4387 if (SUCCEEDED(hrc) && pFramebuffer)
4388 {
4389 hrc = pFramebuffer->COMGETTER(HeightReduction)(&ulHeightReduction); H();
4390 pFramebuffer->Release();
4391 pFramebuffer = NULL;
4392 }
4393 else
4394 {
4395 /* If framebuffer is not available, there is no height reduction. */
4396 ulHeightReduction = 0;
4397 }
4398 InsertConfigInteger(pCfg, "HeightReduction", ulHeightReduction);
4399
4400 /*
4401 * BIOS logo
4402 */
4403 BOOL fFadeIn;
4404 hrc = ptrBiosSettings->COMGETTER(LogoFadeIn)(&fFadeIn); H();
4405 InsertConfigInteger(pCfg, "FadeIn", fFadeIn ? 1 : 0);
4406 BOOL fFadeOut;
4407 hrc = ptrBiosSettings->COMGETTER(LogoFadeOut)(&fFadeOut); H();
4408 InsertConfigInteger(pCfg, "FadeOut", fFadeOut ? 1: 0);
4409 ULONG logoDisplayTime;
4410 hrc = ptrBiosSettings->COMGETTER(LogoDisplayTime)(&logoDisplayTime); H();
4411 InsertConfigInteger(pCfg, "LogoTime", logoDisplayTime);
4412 Bstr bstrLogoImagePath;
4413 hrc = ptrBiosSettings->COMGETTER(LogoImagePath)(bstrLogoImagePath.asOutParam()); H();
4414 InsertConfigString(pCfg, "LogoFile", bstrLogoImagePath);
4415
4416 /*
4417 * Boot menu
4418 */
4419 BIOSBootMenuMode_T eBootMenuMode;
4420 int iShowBootMenu;
4421 hrc = ptrBiosSettings->COMGETTER(BootMenuMode)(&eBootMenuMode); H();
4422 switch (eBootMenuMode)
4423 {
4424 case BIOSBootMenuMode_Disabled: iShowBootMenu = 0; break;
4425 case BIOSBootMenuMode_MenuOnly: iShowBootMenu = 1; break;
4426 default: iShowBootMenu = 2; break;
4427 }
4428 InsertConfigInteger(pCfg, "ShowBootMenu", iShowBootMenu);
4429
4430 /* Attach the display. */
4431 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4432 InsertConfigString(pLunL0, "Driver", "MainDisplay");
4433 InsertConfigNode(pLunL0, "Config", &pCfg);
4434 }
4435 catch (ConfigError &x)
4436 {
4437 // InsertConfig threw something:
4438 return x.m_vrc;
4439 }
4440
4441#undef H
4442
4443 return VINF_SUCCESS;
4444}
4445
4446
4447/**
4448 * Ellipsis to va_list wrapper for calling setVMRuntimeErrorCallback.
4449 */
4450void Console::i_atVMRuntimeErrorCallbackF(uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)
4451{
4452 va_list va;
4453 va_start(va, pszFormat);
4454 i_atVMRuntimeErrorCallback(NULL, this, fFlags, pszErrorId, pszFormat, va);
4455 va_end(va);
4456}
4457
4458/* XXX introduce RT format specifier */
4459static uint64_t formatDiskSize(uint64_t u64Size, const char **pszUnit)
4460{
4461 if (u64Size > INT64_C(5000)*_1G)
4462 {
4463 *pszUnit = "TB";
4464 return u64Size / _1T;
4465 }
4466 else if (u64Size > INT64_C(5000)*_1M)
4467 {
4468 *pszUnit = "GB";
4469 return u64Size / _1G;
4470 }
4471 else
4472 {
4473 *pszUnit = "MB";
4474 return u64Size / _1M;
4475 }
4476}
4477
4478/**
4479 * Checks the location of the given medium for known bugs affecting the usage
4480 * of the host I/O cache setting.
4481 *
4482 * @returns VBox status code.
4483 * @param pMedium The medium to check.
4484 * @param pfUseHostIOCache Where to store the suggested host I/O cache setting.
4485 */
4486int Console::i_checkMediumLocation(IMedium *pMedium, bool *pfUseHostIOCache)
4487{
4488#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4489 /*
4490 * Some sanity checks.
4491 */
4492 RT_NOREF(pfUseHostIOCache);
4493 ComPtr<IMediumFormat> pMediumFormat;
4494 HRESULT hrc = pMedium->COMGETTER(MediumFormat)(pMediumFormat.asOutParam()); H();
4495 ULONG uCaps = 0;
4496 com::SafeArray <MediumFormatCapabilities_T> mediumFormatCap;
4497 hrc = pMediumFormat->COMGETTER(Capabilities)(ComSafeArrayAsOutParam(mediumFormatCap)); H();
4498
4499 for (ULONG j = 0; j < mediumFormatCap.size(); j++)
4500 uCaps |= mediumFormatCap[j];
4501
4502 if (uCaps & MediumFormatCapabilities_File)
4503 {
4504 Bstr bstrFile;
4505 hrc = pMedium->COMGETTER(Location)(bstrFile.asOutParam()); H();
4506 Utf8Str const strFile(bstrFile);
4507
4508 Bstr bstrSnap;
4509 ComPtr<IMachine> pMachine = i_machine();
4510 hrc = pMachine->COMGETTER(SnapshotFolder)(bstrSnap.asOutParam()); H();
4511 Utf8Str const strSnap(bstrSnap);
4512
4513 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
4514 int vrc2 = RTFsQueryType(strFile.c_str(), &enmFsTypeFile);
4515 AssertMsgRCReturn(vrc2, ("Querying the file type of '%s' failed!\n", strFile.c_str()), vrc2);
4516
4517 /* Any VM which hasn't created a snapshot or saved the current state of the VM
4518 * won't have a Snapshot folder yet so no need to log anything about the file system
4519 * type of the non-existent directory in such cases. */
4520 RTFSTYPE enmFsTypeSnap = RTFSTYPE_UNKNOWN;
4521 vrc2 = RTFsQueryType(strSnap.c_str(), &enmFsTypeSnap);
4522 if (RT_SUCCESS(vrc2) && !mfSnapshotFolderDiskTypeShown)
4523 {
4524 LogRel(("File system of '%s' (snapshots) is %s\n", strSnap.c_str(), RTFsTypeName(enmFsTypeSnap)));
4525 mfSnapshotFolderDiskTypeShown = true;
4526 }
4527 LogRel(("File system of '%s' is %s\n", strFile.c_str(), RTFsTypeName(enmFsTypeFile)));
4528 LONG64 i64Size;
4529 hrc = pMedium->COMGETTER(LogicalSize)(&i64Size); H();
4530#ifdef RT_OS_WINDOWS
4531 if ( enmFsTypeFile == RTFSTYPE_FAT
4532 && i64Size >= _4G)
4533 {
4534 const char *pszUnit;
4535 uint64_t u64Print = formatDiskSize((uint64_t)i64Size, &pszUnit);
4536 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
4537 N_("The medium '%s' has a logical size of %RU64%s "
4538 "but the file system the medium is located on seems "
4539 "to be FAT(32) which cannot handle files bigger than 4GB.\n"
4540 "We strongly recommend to put all your virtual disk images and "
4541 "the snapshot folder onto an NTFS partition"),
4542 strFile.c_str(), u64Print, pszUnit);
4543 }
4544#else /* !RT_OS_WINDOWS */
4545 if ( enmFsTypeFile == RTFSTYPE_FAT
4546 || enmFsTypeFile == RTFSTYPE_EXT
4547 || enmFsTypeFile == RTFSTYPE_EXT2
4548 || enmFsTypeFile == RTFSTYPE_EXT3
4549 || enmFsTypeFile == RTFSTYPE_EXT4)
4550 {
4551 RTFILE file;
4552 int vrc = RTFileOpen(&file, strFile.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
4553 if (RT_SUCCESS(vrc))
4554 {
4555 RTFOFF maxSize;
4556 /* Careful: This function will work only on selected local file systems! */
4557 vrc = RTFileQueryMaxSizeEx(file, &maxSize);
4558 RTFileClose(file);
4559 if ( RT_SUCCESS(vrc)
4560 && maxSize > 0
4561 && i64Size > (LONG64)maxSize)
4562 {
4563 const char *pszUnitSiz;
4564 const char *pszUnitMax;
4565 uint64_t u64PrintSiz = formatDiskSize((LONG64)i64Size, &pszUnitSiz);
4566 uint64_t u64PrintMax = formatDiskSize(maxSize, &pszUnitMax);
4567 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected", /* <= not exact but ... */
4568 N_("The medium '%s' has a logical size of %RU64%s "
4569 "but the file system the medium is located on can "
4570 "only handle files up to %RU64%s in theory.\n"
4571 "We strongly recommend to put all your virtual disk "
4572 "images and the snapshot folder onto a proper "
4573 "file system (e.g. ext3) with a sufficient size"),
4574 strFile.c_str(), u64PrintSiz, pszUnitSiz, u64PrintMax, pszUnitMax);
4575 }
4576 }
4577 }
4578#endif /* !RT_OS_WINDOWS */
4579
4580 /*
4581 * Snapshot folder:
4582 * Here we test only for a FAT partition as we had to create a dummy file otherwise
4583 */
4584 if ( enmFsTypeSnap == RTFSTYPE_FAT
4585 && i64Size >= _4G
4586 && !mfSnapshotFolderSizeWarningShown)
4587 {
4588 const char *pszUnit;
4589 uint64_t u64Print = formatDiskSize(i64Size, &pszUnit);
4590 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
4591#ifdef RT_OS_WINDOWS
4592 N_("The snapshot folder of this VM '%s' seems to be located on "
4593 "a FAT(32) file system. The logical size of the medium '%s' "
4594 "(%RU64%s) is bigger than the maximum file size this file "
4595 "system can handle (4GB).\n"
4596 "We strongly recommend to put all your virtual disk images and "
4597 "the snapshot folder onto an NTFS partition"),
4598#else
4599 N_("The snapshot folder of this VM '%s' seems to be located on "
4600 "a FAT(32) file system. The logical size of the medium '%s' "
4601 "(%RU64%s) is bigger than the maximum file size this file "
4602 "system can handle (4GB).\n"
4603 "We strongly recommend to put all your virtual disk images and "
4604 "the snapshot folder onto a proper file system (e.g. ext3)"),
4605#endif
4606 strSnap.c_str(), strFile.c_str(), u64Print, pszUnit);
4607 /* Show this particular warning only once */
4608 mfSnapshotFolderSizeWarningShown = true;
4609 }
4610
4611#ifdef RT_OS_LINUX
4612 /*
4613 * Ext4 bug: Check if the host I/O cache is disabled and the disk image is located
4614 * on an ext4 partition.
4615 * This bug apparently applies to the XFS file system as well.
4616 * Linux 2.6.36 is known to be fixed (tested with 2.6.36-rc4).
4617 */
4618
4619 char szOsRelease[128];
4620 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOsRelease, sizeof(szOsRelease));
4621 bool fKernelHasODirectBug = RT_FAILURE(vrc)
4622 || (RTStrVersionCompare(szOsRelease, "2.6.36-rc4") < 0);
4623
4624 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
4625 && !*pfUseHostIOCache
4626 && fKernelHasODirectBug)
4627 {
4628 if ( enmFsTypeFile == RTFSTYPE_EXT4
4629 || enmFsTypeFile == RTFSTYPE_XFS)
4630 {
4631 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
4632 N_("The host I/O cache for at least one controller is disabled "
4633 "and the medium '%s' for this VM "
4634 "is located on an %s partition. There is a known Linux "
4635 "kernel bug which can lead to the corruption of the virtual "
4636 "disk image under these conditions.\n"
4637 "Either enable the host I/O cache permanently in the VM "
4638 "settings or put the disk image and the snapshot folder "
4639 "onto a different file system.\n"
4640 "The host I/O cache will now be enabled for this medium"),
4641 strFile.c_str(), enmFsTypeFile == RTFSTYPE_EXT4 ? "ext4" : "xfs");
4642 *pfUseHostIOCache = true;
4643 }
4644 else if ( ( enmFsTypeSnap == RTFSTYPE_EXT4
4645 || enmFsTypeSnap == RTFSTYPE_XFS)
4646 && !mfSnapshotFolderExt4WarningShown)
4647 {
4648 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
4649 N_("The host I/O cache for at least one controller is disabled "
4650 "and the snapshot folder for this VM "
4651 "is located on an %s partition. There is a known Linux "
4652 "kernel bug which can lead to the corruption of the virtual "
4653 "disk image under these conditions.\n"
4654 "Either enable the host I/O cache permanently in the VM "
4655 "settings or put the disk image and the snapshot folder "
4656 "onto a different file system.\n"
4657 "The host I/O cache will now be enabled for this medium"),
4658 enmFsTypeSnap == RTFSTYPE_EXT4 ? "ext4" : "xfs");
4659 *pfUseHostIOCache = true;
4660 mfSnapshotFolderExt4WarningShown = true;
4661 }
4662 }
4663
4664 /*
4665 * 2.6.18 bug: Check if the host I/O cache is disabled and the host is running
4666 * Linux 2.6.18. See @bugref{8690}. Apparently the same problem as
4667 * documented in https://lkml.org/lkml/2007/2/1/14. We saw such
4668 * kernel oopses on Linux 2.6.18-416.el5. We don't know when this
4669 * was fixed but we _know_ that 2.6.18 EL5 kernels are affected.
4670 */
4671 bool fKernelAsyncUnreliable = RT_FAILURE(vrc)
4672 || (RTStrVersionCompare(szOsRelease, "2.6.19") < 0);
4673 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
4674 && !*pfUseHostIOCache
4675 && fKernelAsyncUnreliable)
4676 {
4677 i_atVMRuntimeErrorCallbackF(0, "Linux2618TooOld",
4678 N_("The host I/O cache for at least one controller is disabled. "
4679 "There is a known Linux kernel bug which can lead to kernel "
4680 "oopses under heavy load. To our knowledge this bug affects "
4681 "all 2.6.18 kernels.\n"
4682 "Either enable the host I/O cache permanently in the VM "
4683 "settings or switch to a newer host kernel.\n"
4684 "The host I/O cache will now be enabled for this medium"));
4685 *pfUseHostIOCache = true;
4686 }
4687#endif
4688 }
4689#undef H
4690
4691 return VINF_SUCCESS;
4692}
4693
4694/**
4695 * Unmounts the specified medium from the specified device.
4696 *
4697 * @returns VBox status code.
4698 * @param pUVM The usermode VM handle.
4699 * @param pVMM The VMM vtable.
4700 * @param enmBus The storage bus.
4701 * @param enmDevType The device type.
4702 * @param pcszDevice The device emulation.
4703 * @param uInstance Instance of the device.
4704 * @param uLUN The LUN on the device.
4705 * @param fForceUnmount Whether to force unmounting.
4706 */
4707int Console::i_unmountMediumFromGuest(PUVM pUVM, PCVMMR3VTABLE pVMM, StorageBus_T enmBus, DeviceType_T enmDevType,
4708 const char *pcszDevice, unsigned uInstance, unsigned uLUN,
4709 bool fForceUnmount) RT_NOEXCEPT
4710{
4711 /* Unmount existing media only for floppy and DVD drives. */
4712 int vrc = VINF_SUCCESS;
4713 PPDMIBASE pBase;
4714 if (enmBus == StorageBus_USB)
4715 vrc = pVMM->pfnPDMR3UsbQueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
4716 else if ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI || enmBus == StorageBus_VirtioSCSI)
4717 || (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD))
4718 vrc = pVMM->pfnPDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
4719 else /* IDE or Floppy */
4720 vrc = pVMM->pfnPDMR3QueryLun(pUVM, pcszDevice, uInstance, uLUN, &pBase);
4721
4722 if (RT_FAILURE(vrc))
4723 {
4724 if (vrc == VERR_PDM_LUN_NOT_FOUND || vrc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4725 vrc = VINF_SUCCESS;
4726 AssertRC(vrc);
4727 }
4728 else
4729 {
4730 PPDMIMOUNT pIMount = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMOUNT);
4731 AssertReturn(pIMount, VERR_INVALID_POINTER);
4732
4733 /* Unmount the media (but do not eject the medium!) */
4734 vrc = pIMount->pfnUnmount(pIMount, fForceUnmount, false /*=fEject*/);
4735 if (vrc == VERR_PDM_MEDIA_NOT_MOUNTED)
4736 vrc = VINF_SUCCESS;
4737 /* for example if the medium is locked */
4738 else if (RT_FAILURE(vrc))
4739 return vrc;
4740 }
4741
4742 return vrc;
4743}
4744
4745/**
4746 * Removes the currently attached medium driver form the specified device
4747 * taking care of the controlelr specific configs wrt. to the attached driver chain.
4748 *
4749 * @returns VBox status code.
4750 * @param pCtlInst The controler instance node in the CFGM tree.
4751 * @param pcszDevice The device name.
4752 * @param uInstance The device instance.
4753 * @param uLUN The device LUN.
4754 * @param enmBus The storage bus.
4755 * @param fAttachDetach Flag whether this is a change while the VM is running
4756 * @param fHotplug Flag whether the guest should be notified about the device change.
4757 * @param fForceUnmount Flag whether to force unmounting the medium even if it is locked.
4758 * @param pUVM The usermode VM handle.
4759 * @param pVMM The VMM vtable.
4760 * @param enmDevType The device type.
4761 * @param ppLunL0 Where to store the node to attach the new config to on success.
4762 */
4763int Console::i_removeMediumDriverFromVm(PCFGMNODE pCtlInst,
4764 const char *pcszDevice,
4765 unsigned uInstance,
4766 unsigned uLUN,
4767 StorageBus_T enmBus,
4768 bool fAttachDetach,
4769 bool fHotplug,
4770 bool fForceUnmount,
4771 PUVM pUVM,
4772 PCVMMR3VTABLE pVMM,
4773 DeviceType_T enmDevType,
4774 PCFGMNODE *ppLunL0)
4775{
4776 int vrc = VINF_SUCCESS;
4777 bool fAddLun = false;
4778
4779 /* First check if the LUN already exists. */
4780 PCFGMNODE pLunL0 = pVMM->pfnCFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
4781 AssertReturn(!RT_VALID_PTR(pLunL0) || fAttachDetach, VERR_INTERNAL_ERROR);
4782
4783 if (pLunL0)
4784 {
4785 /*
4786 * Unmount the currently mounted medium if we don't just hot remove the
4787 * complete device (SATA) and it supports unmounting (DVD).
4788 */
4789 if ( (enmDevType != DeviceType_HardDisk)
4790 && !fHotplug)
4791 {
4792 vrc = i_unmountMediumFromGuest(pUVM, pVMM, enmBus, enmDevType, pcszDevice, uInstance, uLUN, fForceUnmount);
4793 if (RT_FAILURE(vrc))
4794 return vrc;
4795 }
4796
4797 /*
4798 * Don't detach the SCSI driver when unmounting the current medium
4799 * (we are not ripping out the device but only eject the medium).
4800 */
4801 char *pszDriverDetach = NULL;
4802 if ( !fHotplug
4803 && ( (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD)
4804 || enmBus == StorageBus_SAS
4805 || enmBus == StorageBus_SCSI
4806 || enmBus == StorageBus_VirtioSCSI
4807 || enmBus == StorageBus_USB))
4808 {
4809 /* Get the current attached driver we have to detach. */
4810 PCFGMNODE pDrvLun = pVMM->pfnCFGMR3GetChildF(pCtlInst, "LUN#%u/AttachedDriver/", uLUN);
4811 if (pDrvLun)
4812 {
4813 char szDriver[128];
4814 RT_ZERO(szDriver);
4815 vrc = pVMM->pfnCFGMR3QueryString(pDrvLun, "Driver", &szDriver[0], sizeof(szDriver));
4816 if (RT_SUCCESS(vrc))
4817 pszDriverDetach = RTStrDup(&szDriver[0]);
4818
4819 pLunL0 = pDrvLun;
4820 }
4821 }
4822
4823 if (enmBus == StorageBus_USB)
4824 vrc = pVMM->pfnPDMR3UsbDriverDetach(pUVM, pcszDevice, uInstance, uLUN, pszDriverDetach,
4825 0 /* iOccurence */, fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
4826 else
4827 vrc = pVMM->pfnPDMR3DriverDetach(pUVM, pcszDevice, uInstance, uLUN, pszDriverDetach,
4828 0 /* iOccurence */, fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
4829
4830 if (pszDriverDetach)
4831 {
4832 RTStrFree(pszDriverDetach);
4833 /* Remove the complete node and create new for the new config. */
4834 pVMM->pfnCFGMR3RemoveNode(pLunL0);
4835 pLunL0 = pVMM->pfnCFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
4836 if (pLunL0)
4837 {
4838 try
4839 {
4840 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4841 }
4842 catch (ConfigError &x)
4843 {
4844 // InsertConfig threw something:
4845 return x.m_vrc;
4846 }
4847 }
4848 }
4849 if (vrc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4850 vrc = VINF_SUCCESS;
4851 AssertRCReturn(vrc, vrc);
4852
4853 /*
4854 * Don't remove the LUN except for IDE/floppy/NVMe (which connects directly to the medium driver
4855 * even for DVD devices) or if there is a hotplug event which rips out the complete device.
4856 */
4857 if ( fHotplug
4858 || enmBus == StorageBus_IDE
4859 || enmBus == StorageBus_Floppy
4860 || enmBus == StorageBus_PCIe
4861 || (enmBus == StorageBus_SATA && enmDevType != DeviceType_DVD))
4862 {
4863 fAddLun = true;
4864 pVMM->pfnCFGMR3RemoveNode(pLunL0);
4865 }
4866 }
4867 else
4868 fAddLun = true;
4869
4870 try
4871 {
4872 if (fAddLun)
4873 InsertConfigNodeF(pCtlInst, &pLunL0, "LUN#%u", uLUN);
4874 }
4875 catch (ConfigError &x)
4876 {
4877 // InsertConfig threw something:
4878 return x.m_vrc;
4879 }
4880
4881 if (ppLunL0)
4882 *ppLunL0 = pLunL0;
4883
4884 return vrc;
4885}
4886
4887int Console::i_configMediumAttachment(const char *pcszDevice,
4888 unsigned uInstance,
4889 StorageBus_T enmBus,
4890 bool fUseHostIOCache,
4891 bool fBuiltinIOCache,
4892 bool fInsertDiskIntegrityDrv,
4893 bool fSetupMerge,
4894 unsigned uMergeSource,
4895 unsigned uMergeTarget,
4896 IMediumAttachment *pMediumAtt,
4897 MachineState_T aMachineState,
4898 HRESULT *phrc,
4899 bool fAttachDetach,
4900 bool fForceUnmount,
4901 bool fHotplug,
4902 PUVM pUVM,
4903 PCVMMR3VTABLE pVMM,
4904 DeviceType_T *paLedDevType,
4905 PCFGMNODE *ppLunL0)
4906{
4907 // InsertConfig* throws
4908 try
4909 {
4910 int vrc = VINF_SUCCESS;
4911 HRESULT hrc;
4912 Bstr bstr;
4913 PCFGMNODE pCtlInst = NULL;
4914
4915// #define RC_CHECK() AssertMsgReturn(RT_SUCCESS(vrc), ("vrc=%Rrc\n", vrc), vrc)
4916#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4917
4918 LONG lDev;
4919 hrc = pMediumAtt->COMGETTER(Device)(&lDev); H();
4920 LONG lPort;
4921 hrc = pMediumAtt->COMGETTER(Port)(&lPort); H();
4922 DeviceType_T enmType;
4923 hrc = pMediumAtt->COMGETTER(Type)(&enmType); H();
4924 BOOL fNonRotational;
4925 hrc = pMediumAtt->COMGETTER(NonRotational)(&fNonRotational); H();
4926 BOOL fDiscard;
4927 hrc = pMediumAtt->COMGETTER(Discard)(&fDiscard); H();
4928
4929 if (enmType == DeviceType_DVD)
4930 fInsertDiskIntegrityDrv = false;
4931
4932 unsigned uLUN;
4933 PCFGMNODE pLunL0 = NULL;
4934 hrc = Console::i_storageBusPortDeviceToLun(enmBus, lPort, lDev, uLUN); H();
4935
4936 /* Determine the base path for the device instance. */
4937 if (enmBus != StorageBus_USB)
4938 pCtlInst = pVMM->pfnCFGMR3GetChildF(pVMM->pfnCFGMR3GetRootU(pUVM), "Devices/%s/%u/", pcszDevice, uInstance);
4939 else
4940 {
4941 /* If we hotplug a USB device create a new CFGM tree. */
4942 if (!fHotplug)
4943 pCtlInst = pVMM->pfnCFGMR3GetChildF(pVMM->pfnCFGMR3GetRootU(pUVM), "USB/%s/", pcszDevice);
4944 else
4945 pCtlInst = pVMM->pfnCFGMR3CreateTree(pUVM); /** @todo r=bird: Leaked in error paths! */
4946 }
4947 AssertReturn(pCtlInst, VERR_INTERNAL_ERROR);
4948
4949 if (enmBus == StorageBus_USB)
4950 {
4951 PCFGMNODE pCfg = NULL;
4952
4953 /* Create correct instance. */
4954 if (!fHotplug)
4955 {
4956 if (!fAttachDetach)
4957 InsertConfigNodeF(pCtlInst, &pCtlInst, "%d", lPort);
4958 else
4959 pCtlInst = pVMM->pfnCFGMR3GetChildF(pCtlInst, "%d/", lPort);
4960 }
4961
4962 if (!fAttachDetach)
4963 InsertConfigNode(pCtlInst, "Config", &pCfg);
4964
4965 uInstance = lPort; /* Overwrite uInstance with the correct one. */
4966
4967 /** @todo No LED after hotplugging. */
4968 if (!fHotplug && !fAttachDetach)
4969 {
4970 USBStorageDevice UsbMsd;
4971 UsbMsd.iPort = uInstance;
4972 vrc = RTUuidCreate(&UsbMsd.mUuid);
4973 AssertRCReturn(vrc, vrc);
4974
4975 InsertConfigStringF(pCtlInst, "UUID", "%RTuuid", &UsbMsd.mUuid);
4976
4977 mUSBStorageDevices.push_back(UsbMsd);
4978
4979 /** @todo This LED set is not freed if the device is unplugged. We could
4980 * keep the LED set index in the UsbMsd structure and clean it up in
4981 * i_detachStorageDevice. */
4982 /* Attach the status driver */
4983 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk),
4984 8, &paLedDevType, &mapMediumAttachments, pcszDevice, 0);
4985 }
4986 }
4987
4988 vrc = i_removeMediumDriverFromVm(pCtlInst, pcszDevice, uInstance, uLUN, enmBus, fAttachDetach,
4989 fHotplug, fForceUnmount, pUVM, pVMM, enmType, &pLunL0);
4990 if (RT_FAILURE(vrc))
4991 return vrc;
4992 if (ppLunL0)
4993 *ppLunL0 = pLunL0;
4994
4995 Utf8StrFmt devicePath("%s/%u/LUN#%u", pcszDevice, uInstance, uLUN);
4996 mapMediumAttachments[devicePath] = pMediumAtt;
4997
4998 ComPtr<IMedium> ptrMedium;
4999 hrc = pMediumAtt->COMGETTER(Medium)(ptrMedium.asOutParam()); H();
5000
5001 /*
5002 * 1. Only check this for hard disk images.
5003 * 2. Only check during VM creation and not later, especially not during
5004 * taking an online snapshot!
5005 */
5006 if ( enmType == DeviceType_HardDisk
5007 && ( aMachineState == MachineState_Starting
5008 || aMachineState == MachineState_Restoring))
5009 {
5010 vrc = i_checkMediumLocation(ptrMedium, &fUseHostIOCache);
5011 if (RT_FAILURE(vrc))
5012 return vrc;
5013 }
5014
5015 BOOL fPassthrough = FALSE;
5016 if (ptrMedium.isNotNull())
5017 {
5018 BOOL fHostDrive;
5019 hrc = ptrMedium->COMGETTER(